From: Michael Büsch <mb@bu3sch.de>
Date: Fri, 15 Feb 2008 22:47:47 +0000 (+0000)
Subject: Upgrade b43 and mac80211.
X-Git-Url: http://git.cdn.openwrt.org/?a=commitdiff_plain;h=99aaf500ed5ca39f30cebf79dc0ee9ff1fd8becf;p=openwrt%2Fstaging%2Fwigyori.git

Upgrade b43 and mac80211.

This also temporarly disables hostapd support for mac80211, as hostapd needs patches to compile against latest mac80211.
Will do that in a seperate patch.

SVN-Revision: 10466
---

diff --git a/package/b43/Makefile b/package/b43/Makefile
index c4cc91f5cf..e47d5165eb 100644
--- a/package/b43/Makefile
+++ b/package/b43/Makefile
@@ -23,11 +23,11 @@ PKG_FWV4_SOURCE_URL:=http://downloads.openwrt.org/sources/
 PKG_FWV4_MD5SUM:=a7d8dde3ce474c361143b83e1d9890b1
 
 PKG_FWCUTTER_NAME:=b43-fwcutter
-PKG_FWCUTTER_VERSION=008
+PKG_FWCUTTER_VERSION=011
 
 PKG_FWCUTTER_SOURCE:=$(PKG_FWCUTTER_NAME)-$(PKG_FWCUTTER_VERSION).tar.bz2
-PKG_FWCUTTER_SOURCE_URL:=http://download.berlios.de/bcm43xx/
-PKG_FWCUTTER_MD5SUM:=3f7fbf4f8dcd296c6d1b0d42eab0f9ac
+PKG_FWCUTTER_SOURCE_URL:=http://bu3sch.de/b43/fwcutter/
+PKG_FWCUTTER_MD5SUM:=3db2f4de85a459451f5b391cf67a8d44
 
 define KernelPackage/b43
   SUBMENU:=Wireless Drivers
@@ -43,7 +43,6 @@ endef
 
 EXTRA_KCONFIG:= \
 	CONFIG_B43=m \
-	CONFIG_B43_DMA=y \
 	$(if $(CONFIG_LEDS_TRIGGERS),CONFIG_B43_LEDS=y) \
 
 
@@ -73,6 +72,8 @@ define Build/Prepare
 	$(CP) ./src/* $(PKG_BUILD_DIR)/
 	tar xjf "$(DL_DIR)/$(PKG_FWV4_SOURCE)" -C "$(PKG_BUILD_DIR)"
 	tar xjf "$(DL_DIR)/$(PKG_FWCUTTER_SOURCE)" -C "$(PKG_BUILD_DIR)"
+	$(Build/Patch)
+	$(if $(QUILT),touch $(PKG_BUILD_DIR)/.quilt_used)
 endef
 
 define Build/Configure
diff --git a/package/b43/src/Kconfig b/package/b43/src/Kconfig
index e3c573e56b..1a2141dabd 100644
--- a/package/b43/src/Kconfig
+++ b/package/b43/src/Kconfig
@@ -61,16 +61,28 @@ config B43_PCMCIA
 
 	  If unsure, say N.
 
-# LED support
+config B43_NPHY
+	bool "Pre IEEE 802.11n support (BROKEN)"
+	depends on B43 && EXPERIMENTAL && BROKEN
+	---help---
+	  Support for the IEEE 802.11n draft.
+
+	  THIS IS BROKEN AND DOES NOT WORK YET.
+
+	  SAY N.
+
+# This config option automatically enables b43 LEDS support,
+# if it's possible.
 config B43_LEDS
 	bool
-	depends on B43 && MAC80211_LEDS
+	depends on B43 && MAC80211_LEDS && (LEDS_CLASS = y || LEDS_CLASS = B43)
 	default y
 
-# RFKILL support
+# This config option automatically enables b43 RFKILL support,
+# if it's possible.
 config B43_RFKILL
 	bool
-	depends on B43 && RFKILL && RFKILL_INPUT && INPUT_POLLDEV
+	depends on B43 && (RFKILL = y || RFKILL = B43) && RFKILL_INPUT && (INPUT_POLLDEV = y || INPUT_POLLDEV = B43)
 	default y
 
 config B43_DEBUG
@@ -81,51 +93,3 @@ config B43_DEBUG
 
 	  Say Y, if you want to find out why the driver does not
 	  work for you.
-
-config B43_DMA
-	bool
-	depends on B43
-config B43_PIO
-	bool
-	depends on B43
-
-choice
-	prompt "Broadcom 43xx data transfer mode"
-	depends on B43
-	default B43_DMA_AND_PIO_MODE
-
-config B43_DMA_AND_PIO_MODE
-	bool "DMA + PIO"
-	select B43_DMA
-	select B43_PIO
-	---help---
-	  Include both, Direct Memory Access (DMA) and Programmed I/O (PIO)
-	  data transfer modes.
-	  The actually used mode is selectable through the module
-	  parameter "pio". If the module parameter is pio=0, DMA is used.
-	  Otherwise PIO is used. DMA is default.
-
-	  If unsure, choose this option.
-
-config B43_DMA_MODE
-	bool "DMA (Direct Memory Access) only"
-	select B43_DMA
-	---help---
-	  Only include Direct Memory Access (DMA).
-	  This reduces the size of the driver module, by omitting the PIO code.
-
-config B43_PIO_MODE
-	bool "PIO (Programmed I/O) only"
-	select B43_PIO
-	---help---
-	  Only include Programmed I/O (PIO).
-	  This reduces the size of the driver module, by omitting the DMA code.
-	  Please note that PIO transfers are slow (compared to DMA).
-
-	  Also note that not all devices of the 43xx series support PIO.
-	  The 4306 (Apple Airport Extreme and others) supports PIO, while
-	  the 4318 is known to _not_ support PIO.
-
-	  Only use PIO, if DMA does not work for you.
-
-endchoice
diff --git a/package/b43/src/Makefile b/package/b43/src/Makefile
index 485e59e2df..ac1329dba0 100644
--- a/package/b43/src/Makefile
+++ b/package/b43/src/Makefile
@@ -1,20 +1,16 @@
-# b43 core
 b43-y				+= main.o
 b43-y				+= tables.o
+b43-y				+= tables_nphy.o
 b43-y				+= phy.o
+b43-y				+= nphy.o
 b43-y				+= sysfs.o
 b43-y				+= xmit.o
 b43-y				+= lo.o
-# b43 RFKILL button support
+b43-y				+= wa.o
+b43-y				+= dma.o
 b43-$(CONFIG_B43_RFKILL)	+= rfkill.o
-# b43 LED support
 b43-$(CONFIG_B43_LEDS)		+= leds.o
-# b43 PCMCIA support
 b43-$(CONFIG_B43_PCMCIA)	+= pcmcia.o
-# b43 debugging
 b43-$(CONFIG_B43_DEBUG)		+= debugfs.o
-# b43 DMA and PIO
-b43-$(CONFIG_B43_DMA)		+= dma.o
-b43-$(CONFIG_B43_PIO)		+= pio.o
 
 obj-$(CONFIG_B43)		+= b43.o
diff --git a/package/b43/src/b43.h b/package/b43/src/b43.h
index a28ad230d6..0dc1aaf46b 100644
--- a/package/b43/src/b43.h
+++ b/package/b43/src/b43.h
@@ -35,8 +35,8 @@
 #define B43_MMIO_DMA4_IRQ_MASK		0x44
 #define B43_MMIO_DMA5_REASON		0x48
 #define B43_MMIO_DMA5_IRQ_MASK		0x4C
-#define B43_MMIO_MACCTL			0x120
-#define B43_MMIO_STATUS2_BITFIELD	0x124
+#define B43_MMIO_MACCTL			0x120	/* MAC control */
+#define B43_MMIO_MACCMD			0x124	/* MAC command */
 #define B43_MMIO_GEN_IRQ_REASON		0x128
 #define B43_MMIO_GEN_IRQ_MASK		0x12C
 #define B43_MMIO_RAM_CONTROL		0x130
@@ -50,6 +50,9 @@
 #define B43_MMIO_XMITSTAT_1		0x174
 #define B43_MMIO_REV3PLUS_TSF_LOW	0x180	/* core rev >= 3 only */
 #define B43_MMIO_REV3PLUS_TSF_HIGH	0x184	/* core rev >= 3 only */
+#define B43_MMIO_TSF_CFP_REP		0x188
+#define B43_MMIO_TSF_CFP_START		0x18C
+#define B43_MMIO_TSF_CFP_MAXDUR		0x190
 
 /* 32-bit DMA */
 #define B43_MMIO_DMA32_BASE0		0x200
@@ -65,11 +68,6 @@
 #define B43_MMIO_DMA64_BASE3		0x2C0
 #define B43_MMIO_DMA64_BASE4		0x300
 #define B43_MMIO_DMA64_BASE5		0x340
-/* PIO */
-#define B43_MMIO_PIO1_BASE		0x300
-#define B43_MMIO_PIO2_BASE		0x310
-#define B43_MMIO_PIO3_BASE		0x320
-#define B43_MMIO_PIO4_BASE		0x330
 
 #define B43_MMIO_PHY_VER		0x3E0
 #define B43_MMIO_PHY_RADIO		0x3E2
@@ -88,6 +86,8 @@
 #define B43_MMIO_RADIO_HWENABLED_LO	0x49A
 #define B43_MMIO_GPIO_CONTROL		0x49C
 #define B43_MMIO_GPIO_MASK		0x49E
+#define B43_MMIO_TSF_CFP_START_LOW	0x604
+#define B43_MMIO_TSF_CFP_START_HIGH	0x606
 #define B43_MMIO_TSF_0			0x632	/* core rev < 3 only */
 #define B43_MMIO_TSF_1			0x634	/* core rev < 3 only */
 #define B43_MMIO_TSF_2			0x636	/* core rev < 3 only */
@@ -170,14 +170,17 @@ enum {
 #define B43_SHM_SH_SLOTT		0x0010	/* Slot time */
 #define B43_SHM_SH_DTIMPER		0x0012	/* DTIM period */
 #define B43_SHM_SH_NOSLPZNATDTIM	0x004C	/* NOSLPZNAT DTIM */
-/* SHM_SHARED beacon variables */
+/* SHM_SHARED beacon/AP variables */
 #define B43_SHM_SH_BTL0			0x0018	/* Beacon template length 0 */
 #define B43_SHM_SH_BTL1			0x001A	/* Beacon template length 1 */
 #define B43_SHM_SH_BTSFOFF		0x001C	/* Beacon TSF offset */
 #define B43_SHM_SH_TIMBPOS		0x001E	/* TIM B position in beacon */
+#define B43_SHM_SH_DTIMP		0x0012	/* DTIP period */
+#define B43_SHM_SH_MCASTCOOKIE		0x00A8	/* Last bcast/mcast frame ID */
 #define B43_SHM_SH_SFFBLIM		0x0044	/* Short frame fallback retry limit */
 #define B43_SHM_SH_LFFBLIM		0x0046	/* Long frame fallback retry limit */
 #define B43_SHM_SH_BEACPHYCTL		0x0054	/* Beacon PHY TX control word (see PHY TX control) */
+#define B43_SHM_SH_EXTNPHYCTL		0x00B0	/* Extended bytes for beacon PHY control (N) */
 /* SHM_SHARED ACK/CTS control */
 #define B43_SHM_SH_ACKCTSPHYCTL		0x0022	/* ACK/CTS PHY control word (see PHY TX control) */
 /* SHM_SHARED probe response variables */
@@ -273,6 +276,8 @@ enum {
 #define B43_PHYTYPE_A			0x00
 #define B43_PHYTYPE_B			0x01
 #define B43_PHYTYPE_G			0x02
+#define B43_PHYTYPE_N			0x04
+#define B43_PHYTYPE_LP			0x05
 
 /* PHYRegisters */
 #define B43_PHY_ILT_A_CTRL		0x0072
@@ -319,17 +324,29 @@ enum {
 #define B43_MACCTL_DISCPMQ		0x40000000	/* Discard Power Management Queue */
 #define B43_MACCTL_GMODE		0x80000000	/* G Mode */
 
-/* 802.11 core specific TM State Low flags */
+/* MAC Command bitfield */
+#define B43_MACCMD_BEACON0_VALID	0x00000001	/* Beacon 0 in template RAM is busy/valid */
+#define B43_MACCMD_BEACON1_VALID	0x00000002	/* Beacon 1 in template RAM is busy/valid */
+#define B43_MACCMD_DFQ_VALID		0x00000004	/* Directed frame queue valid (IBSS PS mode, ATIM) */
+#define B43_MACCMD_CCA			0x00000008	/* Clear channel assessment */
+#define B43_MACCMD_BGNOISE		0x00000010	/* Background noise */
+
+/* 802.11 core specific TM State Low (SSB_TMSLOW) flags */
 #define B43_TMSLOW_GMODE		0x20000000	/* G Mode Enable */
-#define B43_TMSLOW_PLLREFSEL		0x00200000	/* PLL Frequency Reference Select */
+#define B43_TMSLOW_PHYCLKSPEED		0x00C00000	/* PHY clock speed mask (N-PHY only) */
+#define  B43_TMSLOW_PHYCLKSPEED_40MHZ	0x00000000	/* 40 MHz PHY */
+#define  B43_TMSLOW_PHYCLKSPEED_80MHZ	0x00400000	/* 80 MHz PHY */
+#define  B43_TMSLOW_PHYCLKSPEED_160MHZ	0x00800000	/* 160 MHz PHY */
+#define B43_TMSLOW_PLLREFSEL		0x00200000	/* PLL Frequency Reference Select (rev >= 5) */
 #define B43_TMSLOW_MACPHYCLKEN		0x00100000	/* MAC PHY Clock Control Enable (rev >= 5) */
 #define B43_TMSLOW_PHYRESET		0x00080000	/* PHY Reset */
 #define B43_TMSLOW_PHYCLKEN		0x00040000	/* PHY Clock Enable */
 
-/* 802.11 core specific TM State High flags */
+/* 802.11 core specific TM State High (SSB_TMSHIGH) flags */
+#define B43_TMSHIGH_DUALBAND_PHY	0x00080000	/* Dualband PHY available */
 #define B43_TMSHIGH_FCLOCK		0x00040000	/* Fast Clock Available (rev >= 5) */
-#define B43_TMSHIGH_APHY		0x00020000	/* A-PHY available (rev >= 5) */
-#define B43_TMSHIGH_GPHY		0x00010000	/* G-PHY available (rev >= 5) */
+#define B43_TMSHIGH_HAVE_5GHZ_PHY	0x00020000	/* 5 GHz PHY available (rev >= 5) */
+#define B43_TMSHIGH_HAVE_2GHZ_PHY	0x00010000	/* 2.4 GHz PHY available (rev >= 5) */
 
 /* Generic-Interrupt reasons. */
 #define B43_IRQ_MAC_SUSPENDED		0x00000001
@@ -391,6 +408,8 @@ enum {
 #define B43_DEFAULT_SHORT_RETRY_LIMIT	7
 #define B43_DEFAULT_LONG_RETRY_LIMIT	4
 
+#define B43_PHY_TX_BADNESS_LIMIT	1000
+
 /* Max size of a security key */
 #define B43_SEC_KEYSIZE			16
 /* Security algorithms. */
@@ -443,10 +462,6 @@ struct b43_phy {
 	u8 possible_phymodes;
 	/* GMODE bit enabled? */
 	bool gmode;
-	/* Possible ieee80211 subsystem hwmodes for this PHY.
-	 * Which mode is selected, depends on thr GMODE enabled bit */
-#define B43_MAX_PHYHWMODES	2
-	struct ieee80211_hw_mode hwmodes[B43_MAX_PHYHWMODES];
 
 	/* Analog Type */
 	u8 analog;
@@ -460,7 +475,6 @@ struct b43_phy {
 	u16 radio_ver;		/* Radio version */
 	u8 radio_rev;		/* Radio revision */
 
-	bool locked;		/* Only used in b43_phy_{un}lock() */
 	bool dyn_tssi_tbl;	/* tssi2dbm is kmalloc()ed. */
 
 	/* ACI (adjacent channel interference) flags. */
@@ -497,11 +511,6 @@ struct b43_phy {
 	s16 lna_gain;		/* LNA */
 	s16 pga_gain;		/* PGA */
 
-	/* PHY lock for core.rev < 3
-	 * This lock is only used by b43_phy_{un}lock()
-	 */
-	spinlock_t lock;
-
 	/* Desired TX power level (in dBm).
 	 * This is set by the user and adjusted in b43_phy_xmitpower(). */
 	u8 power_level;
@@ -512,9 +521,7 @@ struct b43_phy {
 	struct b43_bbatt bbatt;
 	struct b43_rfatt rfatt;
 	u8 tx_control;		/* B43_TXCTL_XXX */
-#ifdef CONFIG_B43_DEBUG
-	bool manual_txpower_control;	/* Manual TX-power control enabled? */
-#endif
+
 	/* Hardware Power Control enabled? */
 	bool hardware_power_control;
 
@@ -542,6 +549,26 @@ struct b43_phy {
 	u16 lofcal;
 
 	u16 initval;		//FIXME rename?
+
+	/* PHY TX errors counter. */
+	atomic_t txerr_cnt;
+
+	/* The device does address auto increment for the OFDM tables.
+	 * We cache the previously used address here and omit the address
+	 * write on the next table access, if possible. */
+	u16 ofdmtab_addr; /* The address currently set in hardware. */
+	enum { /* The last data flow direction. */
+		B43_OFDMTAB_DIRECTION_UNKNOWN = 0,
+		B43_OFDMTAB_DIRECTION_READ,
+		B43_OFDMTAB_DIRECTION_WRITE,
+	} ofdmtab_addr_direction;
+
+#if B43_DEBUG
+	/* Manual TX-power control enabled? */
+	bool manual_txpower_control;
+	/* PHY registers locked by b43_phy_lock()? */
+	bool phy_locked;
+#endif /* B43_DEBUG */
 };
 
 /* Data structures for DMA transmission, per 80211 core. */
@@ -557,14 +584,6 @@ struct b43_dma {
 	struct b43_dmaring *rx_ring3;	/* only available on core.rev < 5 */
 };
 
-/* Data structures for PIO transmission, per 80211 core. */
-struct b43_pio {
-	struct b43_pioqueue *queue0;
-	struct b43_pioqueue *queue1;
-	struct b43_pioqueue *queue2;
-	struct b43_pioqueue *queue3;
-};
-
 /* Context information for a noise calculation (Link Quality). */
 struct b43_noise_calculation {
 	u8 channel_at_start;
@@ -597,18 +616,18 @@ struct b43_wl {
 	/* Pointer to the ieee80211 hardware data structure */
 	struct ieee80211_hw *hw;
 
-	spinlock_t irq_lock;
 	struct mutex mutex;
+	spinlock_t irq_lock;
+	/* Lock for LEDs access. */
 	spinlock_t leds_lock;
+	/* Lock for SHM access. */
+	spinlock_t shm_lock;
 
 	/* We can only have one operating interface (802.11 core)
 	 * at a time. General information about this interface follows.
 	 */
 
-	/* Opaque ID of the operating interface from the ieee80211
-	 * subsystem. Do not modify.
-	 */
-	int if_id;
+	struct ieee80211_vif *vif;
 	/* The MAC address of the operating interface. */
 	u8 mac_addr[ETH_ALEN];
 	/* Current BSSID */
@@ -632,18 +651,33 @@ struct b43_wl {
 	/* List of all wireless devices on this chip */
 	struct list_head devlist;
 	u8 nr_devs;
+
+	bool radiotap_enabled;
+
+	/* The beacon we are currently using (AP or IBSS mode).
+	 * This beacon stuff is protected by the irq_lock. */
+	struct sk_buff *current_beacon;
+	bool beacon0_uploaded;
+	bool beacon1_uploaded;
+};
+
+/* In-memory representation of a cached microcode file. */
+struct b43_firmware_file {
+	const char *filename;
+	const struct firmware *data;
 };
 
 /* Pointers to the firmware data and meta information about it. */
 struct b43_firmware {
 	/* Microcode */
-	const struct firmware *ucode;
+	struct b43_firmware_file ucode;
 	/* PCM code */
-	const struct firmware *pcm;
+	struct b43_firmware_file pcm;
 	/* Initial MMIO values for the firmware */
-	const struct firmware *initvals;
+	struct b43_firmware_file initvals;
 	/* Initial MMIO values for the firmware, band-specific */
-	const struct firmware *initvals_band;
+	struct b43_firmware_file initvals_band;
+
 	/* Firmware revision */
 	u16 rev;
 	/* Firmware patchlevel */
@@ -681,21 +715,16 @@ struct b43_wldev {
 	/* Saved init status for handling suspend. */
 	int suspend_init_status;
 
-	bool __using_pio;	/* Internal, use b43_using_pio(). */
 	bool bad_frames_preempt;	/* Use "Bad Frames Preemption" (default off) */
-	bool reg124_set_0x4;	/* Some variable to keep track of IRQ stuff. */
-	bool short_preamble;	/* TRUE, if short preamble is enabled. */
+	bool dfq_valid;		/* Directed frame queue valid (IBSS PS mode, ATIM) */
 	bool short_slot;	/* TRUE, if short slot timing is enabled. */
 	bool radio_hw_enable;	/* saved state of radio hardware enabled state */
 
 	/* PHY/Radio device. */
 	struct b43_phy phy;
-	union {
-		/* DMA engines. */
-		struct b43_dma dma;
-		/* PIO engines. */
-		struct b43_pio pio;
-	};
+
+	/* DMA engines. */
+	struct b43_dma dma;
 
 	/* Various statistics about the physical device. */
 	struct b43_stats stats;
@@ -730,9 +759,6 @@ struct b43_wldev {
 	u8 max_nr_keys;
 	struct b43_key key[58];
 
-	/* Cached beacon template while uploading the template. */
-	struct sk_buff *cached_beacon;
-
 	/* Firmware data */
 	struct b43_firmware fw;
 
@@ -750,28 +776,6 @@ static inline struct b43_wl *hw_to_b43_wl(struct ieee80211_hw *hw)
 	return hw->priv;
 }
 
-/* Helper function, which returns a boolean.
- * TRUE, if PIO is used; FALSE, if DMA is used.
- */
-#if defined(CONFIG_B43_DMA) && defined(CONFIG_B43_PIO)
-static inline int b43_using_pio(struct b43_wldev *dev)
-{
-	return dev->__using_pio;
-}
-#elif defined(CONFIG_B43_DMA)
-static inline int b43_using_pio(struct b43_wldev *dev)
-{
-	return 0;
-}
-#elif defined(CONFIG_B43_PIO)
-static inline int b43_using_pio(struct b43_wldev *dev)
-{
-	return 1;
-}
-#else
-# error "Using neither DMA nor PIO? Confused..."
-#endif
-
 static inline struct b43_wldev *dev_to_b43_wldev(struct device *dev)
 {
 	struct ssb_device *ssb_dev = dev_to_ssb_dev(dev);
diff --git a/package/b43/src/debugfs.c b/package/b43/src/debugfs.c
index 734e70e1a0..e38ed0fe72 100644
--- a/package/b43/src/debugfs.c
+++ b/package/b43/src/debugfs.c
@@ -34,7 +34,6 @@
 #include "main.h"
 #include "debugfs.h"
 #include "dma.h"
-#include "pio.h"
 #include "xmit.h"
 
 
@@ -128,7 +127,7 @@ static ssize_t shm_read_file(struct b43_wldev *dev,
 	__le16 *le16buf = (__le16 *)buf;
 
 	for (i = 0; i < 0x1000; i++) {
-		if (bufsize <= 0)
+		if (bufsize < sizeof(tmp))
 			break;
 		tmp = b43_shm_read16(dev, B43_SHM_SHARED, 2 * i);
 		le16buf[i] = cpu_to_le16(tmp);
@@ -223,8 +222,6 @@ out:
 static int txpower_g_write_file(struct b43_wldev *dev,
 				const char *buf, size_t count)
 {
-	unsigned long phy_flags;
-
 	if (dev->phy.type != B43_PHYTYPE_G)
 		return -ENODEV;
 	if ((count >= 4) && (memcmp(buf, "auto", 4) == 0)) {
@@ -248,12 +245,12 @@ static int txpower_g_write_file(struct b43_wldev *dev,
 			dev->phy.tx_control |= B43_TXCTL_PA2DB;
 		if (pa3db)
 			dev->phy.tx_control |= B43_TXCTL_PA3DB;
-		b43_phy_lock(dev, phy_flags);
+		b43_phy_lock(dev);
 		b43_radio_lock(dev);
 		b43_set_txpower_g(dev, &dev->phy.bbatt,
 				  &dev->phy.rfatt, dev->phy.tx_control);
 		b43_radio_unlock(dev);
-		b43_phy_unlock(dev, phy_flags);
+		b43_phy_unlock(dev);
 	}
 
 	return 0;
@@ -352,7 +349,7 @@ static ssize_t b43_debugfs_read(struct file *file, char __user *userbuf,
 	struct b43_wldev *dev;
 	struct b43_debugfs_fops *dfops;
 	struct b43_dfs_file *dfile;
-	ssize_t ret;
+	ssize_t uninitialized_var(ret);
 	char *buf;
 	const size_t bufsize = 1024 * 128;
 	const size_t buforder = get_order(bufsize);
diff --git a/package/b43/src/dma.c b/package/b43/src/dma.c
index 5e8f8ac0f1..3dfb28a34b 100644
--- a/package/b43/src/dma.c
+++ b/package/b43/src/dma.c
@@ -37,6 +37,8 @@
 #include <linux/pci.h>
 #include <linux/delay.h>
 #include <linux/skbuff.h>
+#include <linux/etherdevice.h>
+
 
 /* 32bit DMA ops. */
 static
@@ -165,7 +167,7 @@ static void op64_fill_descriptor(struct b43_dmaring *ring,
 	addrhi = (((u64) dmaaddr >> 32) & ~SSB_DMA_TRANSLATION_MASK);
 	addrext = (((u64) dmaaddr >> 32) & SSB_DMA_TRANSLATION_MASK)
 	    >> SSB_DMA_TRANSLATION_SHIFT;
-	addrhi |= ssb_dma_translation(ring->dev->dev);
+	addrhi |= (ssb_dma_translation(ring->dev->dev) << 1);
 	if (slot == ring->nr_slots - 1)
 		ctl0 |= B43_DMA64_DCTL0_DTABLEEND;
 	if (start)
@@ -315,29 +317,27 @@ static struct b43_dmaring *priority_to_txring(struct b43_wldev *dev,
 	case 3:
 		ring = dev->dma.tx_ring0;
 		break;
-	case 4:
-		ring = dev->dma.tx_ring4;
-		break;
-	case 5:
-		ring = dev->dma.tx_ring5;
-		break;
 	}
 
 	return ring;
 }
 
-/* Bcm43xx-ring to mac80211-queue mapping */
+/* b43-ring to mac80211-queue mapping */
 static inline int txring_to_priority(struct b43_dmaring *ring)
 {
-	static const u8 idx_to_prio[] = { 3, 2, 1, 0, 4, 5, };
+	static const u8 idx_to_prio[] = { 3, 2, 1, 0, };
+	unsigned int index;
 
 /*FIXME: have only one queue, for now */
 	return 0;
 
-	return idx_to_prio[ring->index];
+	index = ring->index;
+	if (B43_WARN_ON(index >= ARRAY_SIZE(idx_to_prio)))
+		index = 0;
+	return idx_to_prio[index];
 }
 
-u16 b43_dmacontroller_base(int dma64bit, int controller_idx)
+static u16 b43_dmacontroller_base(enum b43_dmatype type, int controller_idx)
 {
 	static const u16 map64[] = {
 		B43_MMIO_DMA64_BASE0,
@@ -356,7 +356,7 @@ u16 b43_dmacontroller_base(int dma64bit, int controller_idx)
 		B43_MMIO_DMA32_BASE5,
 	};
 
-	if (dma64bit) {
+	if (type == B43_DMA_64BIT) {
 		B43_WARN_ON(!(controller_idx >= 0 &&
 			      controller_idx < ARRAY_SIZE(map64)));
 		return map64[controller_idx];
@@ -426,9 +426,21 @@ static inline
 static int alloc_ringmemory(struct b43_dmaring *ring)
 {
 	struct device *dev = ring->dev->dev->dev;
-
+	gfp_t flags = GFP_KERNEL;
+
+	/* The specs call for 4K buffers for 30- and 32-bit DMA with 4K
+	 * alignment and 8K buffers for 64-bit DMA with 8K alignment. Testing
+	 * has shown that 4K is sufficient for the latter as long as the buffer
+	 * does not cross an 8K boundary.
+	 *
+	 * For unknown reasons - possibly a hardware error - the BCM4311 rev
+	 * 02, which uses 64-bit DMA, needs the ring buffer in very low memory,
+	 * which accounts for the GFP_DMA flag below.
+	 */
+	if (ring->type == B43_DMA_64BIT)
+		flags |= GFP_DMA;
 	ring->descbase = dma_alloc_coherent(dev, B43_DMA_RINGMEMSIZE,
-					    &(ring->dmabase), GFP_KERNEL);
+					    &(ring->dmabase), flags);
 	if (!ring->descbase) {
 		b43err(ring->dev->wl, "DMA ringmemory allocation failed\n");
 		return -ENOMEM;
@@ -447,7 +459,8 @@ static void free_ringmemory(struct b43_dmaring *ring)
 }
 
 /* Reset the RX DMA channel */
-int b43_dmacontroller_rx_reset(struct b43_wldev *dev, u16 mmio_base, int dma64)
+static int b43_dmacontroller_rx_reset(struct b43_wldev *dev, u16 mmio_base,
+				      enum b43_dmatype type)
 {
 	int i;
 	u32 value;
@@ -455,12 +468,13 @@ int b43_dmacontroller_rx_reset(struct b43_wldev *dev, u16 mmio_base, int dma64)
 
 	might_sleep();
 
-	offset = dma64 ? B43_DMA64_RXCTL : B43_DMA32_RXCTL;
+	offset = (type == B43_DMA_64BIT) ? B43_DMA64_RXCTL : B43_DMA32_RXCTL;
 	b43_write32(dev, mmio_base + offset, 0);
 	for (i = 0; i < 10; i++) {
-		offset = dma64 ? B43_DMA64_RXSTATUS : B43_DMA32_RXSTATUS;
+		offset = (type == B43_DMA_64BIT) ? B43_DMA64_RXSTATUS :
+						   B43_DMA32_RXSTATUS;
 		value = b43_read32(dev, mmio_base + offset);
-		if (dma64) {
+		if (type == B43_DMA_64BIT) {
 			value &= B43_DMA64_RXSTAT;
 			if (value == B43_DMA64_RXSTAT_DISABLED) {
 				i = -1;
@@ -483,8 +497,9 @@ int b43_dmacontroller_rx_reset(struct b43_wldev *dev, u16 mmio_base, int dma64)
 	return 0;
 }
 
-/* Reset the RX DMA channel */
-int b43_dmacontroller_tx_reset(struct b43_wldev *dev, u16 mmio_base, int dma64)
+/* Reset the TX DMA channel */
+static int b43_dmacontroller_tx_reset(struct b43_wldev *dev, u16 mmio_base,
+				      enum b43_dmatype type)
 {
 	int i;
 	u32 value;
@@ -493,9 +508,10 @@ int b43_dmacontroller_tx_reset(struct b43_wldev *dev, u16 mmio_base, int dma64)
 	might_sleep();
 
 	for (i = 0; i < 10; i++) {
-		offset = dma64 ? B43_DMA64_TXSTATUS : B43_DMA32_TXSTATUS;
+		offset = (type == B43_DMA_64BIT) ? B43_DMA64_TXSTATUS :
+						   B43_DMA32_TXSTATUS;
 		value = b43_read32(dev, mmio_base + offset);
-		if (dma64) {
+		if (type == B43_DMA_64BIT) {
 			value &= B43_DMA64_TXSTAT;
 			if (value == B43_DMA64_TXSTAT_DISABLED ||
 			    value == B43_DMA64_TXSTAT_IDLEWAIT ||
@@ -510,12 +526,13 @@ int b43_dmacontroller_tx_reset(struct b43_wldev *dev, u16 mmio_base, int dma64)
 		}
 		msleep(1);
 	}
-	offset = dma64 ? B43_DMA64_TXCTL : B43_DMA32_TXCTL;
+	offset = (type == B43_DMA_64BIT) ? B43_DMA64_TXCTL : B43_DMA32_TXCTL;
 	b43_write32(dev, mmio_base + offset, 0);
 	for (i = 0; i < 10; i++) {
-		offset = dma64 ? B43_DMA64_TXSTATUS : B43_DMA32_TXSTATUS;
+		offset = (type == B43_DMA_64BIT) ? B43_DMA64_TXSTATUS :
+						   B43_DMA32_TXSTATUS;
 		value = b43_read32(dev, mmio_base + offset);
-		if (dma64) {
+		if (type == B43_DMA_64BIT) {
 			value &= B43_DMA64_TXSTAT;
 			if (value == B43_DMA64_TXSTAT_DISABLED) {
 				i = -1;
@@ -540,6 +557,33 @@ int b43_dmacontroller_tx_reset(struct b43_wldev *dev, u16 mmio_base, int dma64)
 	return 0;
 }
 
+/* Check if a DMA mapping address is invalid. */
+static bool b43_dma_mapping_error(struct b43_dmaring *ring,
+				  dma_addr_t addr,
+				  size_t buffersize)
+{
+	if (unlikely(dma_mapping_error(addr)))
+		return 1;
+
+	switch (ring->type) {
+	case B43_DMA_30BIT:
+		if ((u64)addr + buffersize > (1ULL << 30))
+			return 1;
+		break;
+	case B43_DMA_32BIT:
+		if ((u64)addr + buffersize > (1ULL << 32))
+			return 1;
+		break;
+	case B43_DMA_64BIT:
+		/* Currently we can't have addresses beyond
+		 * 64bit in the kernel. */
+		break;
+	}
+
+	/* The address is OK. */
+	return 0;
+}
+
 static int setup_rx_descbuffer(struct b43_dmaring *ring,
 			       struct b43_dmadesc_generic *desc,
 			       struct b43_dmadesc_meta *meta, gfp_t gfp_flags)
@@ -555,7 +599,7 @@ static int setup_rx_descbuffer(struct b43_dmaring *ring,
 	if (unlikely(!skb))
 		return -ENOMEM;
 	dmaaddr = map_descbuffer(ring, skb->data, ring->rx_buffersize, 0);
-	if (dma_mapping_error(dmaaddr)) {
+	if (b43_dma_mapping_error(ring, dmaaddr, ring->rx_buffersize)) {
 		/* ugh. try to realloc in zone_dma */
 		gfp_flags |= GFP_DMA;
 
@@ -568,7 +612,7 @@ static int setup_rx_descbuffer(struct b43_dmaring *ring,
 					 ring->rx_buffersize, 0);
 	}
 
-	if (dma_mapping_error(dmaaddr)) {
+	if (b43_dma_mapping_error(ring, dmaaddr, ring->rx_buffersize)) {
 		dev_kfree_skb_any(skb);
 		return -EIO;
 	}
@@ -633,7 +677,7 @@ static int dmacontroller_setup(struct b43_dmaring *ring)
 	u32 trans = ssb_dma_translation(ring->dev->dev);
 
 	if (ring->tx) {
-		if (ring->dma64) {
+		if (ring->type == B43_DMA_64BIT) {
 			u64 ringbase = (u64) (ring->dmabase);
 
 			addrext = ((ringbase >> 32) & SSB_DMA_TRANSLATION_MASK)
@@ -647,7 +691,7 @@ static int dmacontroller_setup(struct b43_dmaring *ring)
 			b43_dma_write(ring, B43_DMA64_TXRINGHI,
 				      ((ringbase >> 32) &
 				       ~SSB_DMA_TRANSLATION_MASK)
-				      | trans);
+				      | (trans << 1));
 		} else {
 			u32 ringbase = (u32) (ring->dmabase);
 
@@ -665,7 +709,7 @@ static int dmacontroller_setup(struct b43_dmaring *ring)
 		err = alloc_initial_descbuffers(ring);
 		if (err)
 			goto out;
-		if (ring->dma64) {
+		if (ring->type == B43_DMA_64BIT) {
 			u64 ringbase = (u64) (ring->dmabase);
 
 			addrext = ((ringbase >> 32) & SSB_DMA_TRANSLATION_MASK)
@@ -680,8 +724,9 @@ static int dmacontroller_setup(struct b43_dmaring *ring)
 			b43_dma_write(ring, B43_DMA64_RXRINGHI,
 				      ((ringbase >> 32) &
 				       ~SSB_DMA_TRANSLATION_MASK)
-				      | trans);
-			b43_dma_write(ring, B43_DMA64_RXINDEX, 200);
+				      | (trans << 1));
+			b43_dma_write(ring, B43_DMA64_RXINDEX, ring->nr_slots *
+				      sizeof(struct b43_dmadesc64));
 		} else {
 			u32 ringbase = (u32) (ring->dmabase);
 
@@ -695,11 +740,12 @@ static int dmacontroller_setup(struct b43_dmaring *ring)
 			b43_dma_write(ring, B43_DMA32_RXRING,
 				      (ringbase & ~SSB_DMA_TRANSLATION_MASK)
 				      | trans);
-			b43_dma_write(ring, B43_DMA32_RXINDEX, 200);
+			b43_dma_write(ring, B43_DMA32_RXINDEX, ring->nr_slots *
+				      sizeof(struct b43_dmadesc32));
 		}
 	}
 
-      out:
+out:
 	return err;
 }
 
@@ -708,16 +754,16 @@ static void dmacontroller_cleanup(struct b43_dmaring *ring)
 {
 	if (ring->tx) {
 		b43_dmacontroller_tx_reset(ring->dev, ring->mmio_base,
-					   ring->dma64);
-		if (ring->dma64) {
+					   ring->type);
+		if (ring->type == B43_DMA_64BIT) {
 			b43_dma_write(ring, B43_DMA64_TXRINGLO, 0);
 			b43_dma_write(ring, B43_DMA64_TXRINGHI, 0);
 		} else
 			b43_dma_write(ring, B43_DMA32_TXRING, 0);
 	} else {
 		b43_dmacontroller_rx_reset(ring->dev, ring->mmio_base,
-					   ring->dma64);
-		if (ring->dma64) {
+					   ring->type);
+		if (ring->type == B43_DMA_64BIT) {
 			b43_dma_write(ring, B43_DMA64_RXRINGLO, 0);
 			b43_dma_write(ring, B43_DMA64_RXRINGHI, 0);
 		} else
@@ -772,7 +818,8 @@ static u64 supported_dma_mask(struct b43_wldev *dev)
 static
 struct b43_dmaring *b43_setup_dmaring(struct b43_wldev *dev,
 				      int controller_index,
-				      int for_tx, int dma64)
+				      int for_tx,
+				      enum b43_dmatype type)
 {
 	struct b43_dmaring *ring;
 	int err;
@@ -782,6 +829,7 @@ struct b43_dmaring *b43_setup_dmaring(struct b43_wldev *dev,
 	ring = kzalloc(sizeof(*ring), GFP_KERNEL);
 	if (!ring)
 		goto out;
+	ring->type = type;
 
 	nr_slots = B43_RXRING_SLOTS;
 	if (for_tx)
@@ -793,7 +841,7 @@ struct b43_dmaring *b43_setup_dmaring(struct b43_wldev *dev,
 		goto err_kfree_ring;
 	if (for_tx) {
 		ring->txhdr_cache = kcalloc(nr_slots,
-					    sizeof(struct b43_txhdr_fw4),
+					    b43_txhdr_size(dev),
 					    GFP_KERNEL);
 		if (!ring->txhdr_cache)
 			goto err_kfree_meta;
@@ -801,39 +849,38 @@ struct b43_dmaring *b43_setup_dmaring(struct b43_wldev *dev,
 		/* test for ability to dma to txhdr_cache */
 		dma_test = dma_map_single(dev->dev->dev,
 					  ring->txhdr_cache,
-					  sizeof(struct b43_txhdr_fw4),
+					  b43_txhdr_size(dev),
 					  DMA_TO_DEVICE);
 
-		if (dma_mapping_error(dma_test)) {
+		if (b43_dma_mapping_error(ring, dma_test, b43_txhdr_size(dev))) {
 			/* ugh realloc */
 			kfree(ring->txhdr_cache);
 			ring->txhdr_cache = kcalloc(nr_slots,
-						    sizeof(struct
-							   b43_txhdr_fw4),
+						    b43_txhdr_size(dev),
 						    GFP_KERNEL | GFP_DMA);
 			if (!ring->txhdr_cache)
 				goto err_kfree_meta;
 
 			dma_test = dma_map_single(dev->dev->dev,
 						  ring->txhdr_cache,
-						  sizeof(struct b43_txhdr_fw4),
+						  b43_txhdr_size(dev),
 						  DMA_TO_DEVICE);
 
-			if (dma_mapping_error(dma_test))
+			if (b43_dma_mapping_error(ring, dma_test,
+						  b43_txhdr_size(dev)))
 				goto err_kfree_txhdr_cache;
 		}
 
 		dma_unmap_single(dev->dev->dev,
-				 dma_test, sizeof(struct b43_txhdr_fw4),
+				 dma_test, b43_txhdr_size(dev),
 				 DMA_TO_DEVICE);
 	}
 
 	ring->dev = dev;
 	ring->nr_slots = nr_slots;
-	ring->mmio_base = b43_dmacontroller_base(dma64, controller_index);
+	ring->mmio_base = b43_dmacontroller_base(type, controller_index);
 	ring->index = controller_index;
-	ring->dma64 = !!dma64;
-	if (dma64)
+	if (type == B43_DMA_64BIT)
 		ring->ops = &dma64_ops;
 	else
 		ring->ops = &dma32_ops;
@@ -883,8 +930,8 @@ static void b43_destroy_dmaring(struct b43_dmaring *ring)
 	if (!ring)
 		return;
 
-	b43dbg(ring->dev->wl, "DMA-%s 0x%04X (%s) max used slots: %d/%d\n",
-	       (ring->dma64) ? "64" : "32",
+	b43dbg(ring->dev->wl, "DMA-%u 0x%04X (%s) max used slots: %d/%d\n",
+	       (unsigned int)(ring->type),
 	       ring->mmio_base,
 	       (ring->tx) ? "TX" : "RX", ring->max_used_slots, ring->nr_slots);
 	/* Device IRQs are disabled prior entering this function,
@@ -901,11 +948,7 @@ static void b43_destroy_dmaring(struct b43_dmaring *ring)
 
 void b43_dma_free(struct b43_wldev *dev)
 {
-	struct b43_dma *dma;
-
-	if (b43_using_pio(dev))
-		return;
-	dma = &dev->dma;
+	struct b43_dma *dma = &dev->dma;
 
 	b43_destroy_dmaring(dma->rx_ring3);
 	dma->rx_ring3 = NULL;
@@ -932,74 +975,78 @@ int b43_dma_init(struct b43_wldev *dev)
 	struct b43_dmaring *ring;
 	int err;
 	u64 dmamask;
-	int dma64 = 0;
+	enum b43_dmatype type;
 
 	dmamask = supported_dma_mask(dev);
-	if (dmamask == DMA_64BIT_MASK)
-		dma64 = 1;
-
+	switch (dmamask) {
+	default:
+		B43_WARN_ON(1);
+	case DMA_30BIT_MASK:
+		type = B43_DMA_30BIT;
+		break;
+	case DMA_32BIT_MASK:
+		type = B43_DMA_32BIT;
+		break;
+	case DMA_64BIT_MASK:
+		type = B43_DMA_64BIT;
+		break;
+	}
 	err = ssb_dma_set_mask(dev->dev, dmamask);
 	if (err) {
-#ifdef B43_PIO
-		b43warn(dev->wl, "DMA for this device not supported. "
-			"Falling back to PIO\n");
-		dev->__using_pio = 1;
-		return -EAGAIN;
-#else
-		b43err(dev->wl, "DMA for this device not supported and "
-		       "no PIO support compiled in\n");
+		b43err(dev->wl, "The machine/kernel does not support "
+		       "the required DMA mask (0x%08X%08X)\n",
+		       (unsigned int)((dmamask & 0xFFFFFFFF00000000ULL) >> 32),
+		       (unsigned int)(dmamask & 0x00000000FFFFFFFFULL));
 		return -EOPNOTSUPP;
-#endif
 	}
 
 	err = -ENOMEM;
 	/* setup TX DMA channels. */
-	ring = b43_setup_dmaring(dev, 0, 1, dma64);
+	ring = b43_setup_dmaring(dev, 0, 1, type);
 	if (!ring)
 		goto out;
 	dma->tx_ring0 = ring;
 
-	ring = b43_setup_dmaring(dev, 1, 1, dma64);
+	ring = b43_setup_dmaring(dev, 1, 1, type);
 	if (!ring)
 		goto err_destroy_tx0;
 	dma->tx_ring1 = ring;
 
-	ring = b43_setup_dmaring(dev, 2, 1, dma64);
+	ring = b43_setup_dmaring(dev, 2, 1, type);
 	if (!ring)
 		goto err_destroy_tx1;
 	dma->tx_ring2 = ring;
 
-	ring = b43_setup_dmaring(dev, 3, 1, dma64);
+	ring = b43_setup_dmaring(dev, 3, 1, type);
 	if (!ring)
 		goto err_destroy_tx2;
 	dma->tx_ring3 = ring;
 
-	ring = b43_setup_dmaring(dev, 4, 1, dma64);
+	ring = b43_setup_dmaring(dev, 4, 1, type);
 	if (!ring)
 		goto err_destroy_tx3;
 	dma->tx_ring4 = ring;
 
-	ring = b43_setup_dmaring(dev, 5, 1, dma64);
+	ring = b43_setup_dmaring(dev, 5, 1, type);
 	if (!ring)
 		goto err_destroy_tx4;
 	dma->tx_ring5 = ring;
 
 	/* setup RX DMA channels. */
-	ring = b43_setup_dmaring(dev, 0, 0, dma64);
+	ring = b43_setup_dmaring(dev, 0, 0, type);
 	if (!ring)
 		goto err_destroy_tx5;
 	dma->rx_ring0 = ring;
 
 	if (dev->dev->id.revision < 5) {
-		ring = b43_setup_dmaring(dev, 3, 0, dma64);
+		ring = b43_setup_dmaring(dev, 3, 0, type);
 		if (!ring)
 			goto err_destroy_rx0;
 		dma->rx_ring3 = ring;
 	}
 
-	b43dbg(dev->wl, "%d-bit DMA initialized\n",
-	       (dmamask == DMA_64BIT_MASK) ? 64 :
-	       (dmamask == DMA_32BIT_MASK) ? 32 : 30);
+	b43dbg(dev->wl, "%u-bit DMA initialized\n",
+	       (unsigned int)type);
 	err = 0;
       out:
 	return err;
@@ -1038,26 +1085,30 @@ static u16 generate_cookie(struct b43_dmaring *ring, int slot)
 	 * in the lower 12 bits.
 	 * Note that the cookie must never be 0, as this
 	 * is a special value used in RX path.
+	 * It can also not be 0xFFFF because that is special
+	 * for multicast frames.
 	 */
 	switch (ring->index) {
 	case 0:
-		cookie = 0xA000;
+		cookie = 0x1000;
 		break;
 	case 1:
-		cookie = 0xB000;
+		cookie = 0x2000;
 		break;
 	case 2:
-		cookie = 0xC000;
+		cookie = 0x3000;
 		break;
 	case 3:
-		cookie = 0xD000;
+		cookie = 0x4000;
 		break;
 	case 4:
-		cookie = 0xE000;
+		cookie = 0x5000;
 		break;
 	case 5:
-		cookie = 0xF000;
+		cookie = 0x6000;
 		break;
+	default:
+		B43_WARN_ON(1);
 	}
 	B43_WARN_ON(slot & ~0x0FFF);
 	cookie |= (u16) slot;
@@ -1073,22 +1124,22 @@ struct b43_dmaring *parse_cookie(struct b43_wldev *dev, u16 cookie, int *slot)
 	struct b43_dmaring *ring = NULL;
 
 	switch (cookie & 0xF000) {
-	case 0xA000:
+	case 0x1000:
 		ring = dma->tx_ring0;
 		break;
-	case 0xB000:
+	case 0x2000:
 		ring = dma->tx_ring1;
 		break;
-	case 0xC000:
+	case 0x3000:
 		ring = dma->tx_ring2;
 		break;
-	case 0xD000:
+	case 0x4000:
 		ring = dma->tx_ring3;
 		break;
-	case 0xE000:
+	case 0x5000:
 		ring = dma->tx_ring4;
 		break;
-	case 0xF000:
+	case 0x6000:
 		ring = dma->tx_ring5;
 		break;
 	default:
@@ -1106,32 +1157,45 @@ static int dma_tx_fragment(struct b43_dmaring *ring,
 {
 	const struct b43_dma_ops *ops = ring->ops;
 	u8 *header;
-	int slot;
+	int slot, old_top_slot, old_used_slots;
 	int err;
 	struct b43_dmadesc_generic *desc;
 	struct b43_dmadesc_meta *meta;
 	struct b43_dmadesc_meta *meta_hdr;
 	struct sk_buff *bounce_skb;
+	u16 cookie;
+	size_t hdrsize = b43_txhdr_size(ring->dev);
 
 #define SLOTS_PER_PACKET  2
 	B43_WARN_ON(skb_shinfo(skb)->nr_frags);
 
+	old_top_slot = ring->current_slot;
+	old_used_slots = ring->used_slots;
+
 	/* Get a slot for the header. */
 	slot = request_slot(ring);
 	desc = ops->idx2desc(ring, slot, &meta_hdr);
 	memset(meta_hdr, 0, sizeof(*meta_hdr));
 
-	header = &(ring->txhdr_cache[slot * sizeof(struct b43_txhdr_fw4)]);
-	b43_generate_txhdr(ring->dev, header,
-			   skb->data, skb->len, ctl,
-			   generate_cookie(ring, slot));
+	header = &(ring->txhdr_cache[slot * hdrsize]);
+	cookie = generate_cookie(ring, slot);
+	err = b43_generate_txhdr(ring->dev, header,
+				 skb->data, skb->len, ctl, cookie);
+	if (unlikely(err)) {
+		ring->current_slot = old_top_slot;
+		ring->used_slots = old_used_slots;
+		return err;
+	}
 
 	meta_hdr->dmaaddr = map_descbuffer(ring, (unsigned char *)header,
-					   sizeof(struct b43_txhdr_fw4), 1);
-	if (dma_mapping_error(meta_hdr->dmaaddr))
+					   hdrsize, 1);
+	if (b43_dma_mapping_error(ring, meta_hdr->dmaaddr, hdrsize)) {
+		ring->current_slot = old_top_slot;
+		ring->used_slots = old_used_slots;
 		return -EIO;
+	}
 	ops->fill_descriptor(ring, desc, meta_hdr->dmaaddr,
-			     sizeof(struct b43_txhdr_fw4), 1, 0, 0);
+			     hdrsize, 1, 0, 0);
 
 	/* Get a slot for the payload. */
 	slot = request_slot(ring);
@@ -1144,9 +1208,11 @@ static int dma_tx_fragment(struct b43_dmaring *ring,
 
 	meta->dmaaddr = map_descbuffer(ring, skb->data, skb->len, 1);
 	/* create a bounce buffer in zone_dma on mapping failure. */
-	if (dma_mapping_error(meta->dmaaddr)) {
+	if (b43_dma_mapping_error(ring, meta->dmaaddr, skb->len)) {
 		bounce_skb = __dev_alloc_skb(skb->len, GFP_ATOMIC | GFP_DMA);
 		if (!bounce_skb) {
+			ring->current_slot = old_top_slot;
+			ring->used_slots = old_used_slots;
 			err = -ENOMEM;
 			goto out_unmap_hdr;
 		}
@@ -1156,7 +1222,9 @@ static int dma_tx_fragment(struct b43_dmaring *ring,
 		skb = bounce_skb;
 		meta->skb = skb;
 		meta->dmaaddr = map_descbuffer(ring, skb->data, skb->len, 1);
-		if (dma_mapping_error(meta->dmaaddr)) {
+		if (b43_dma_mapping_error(ring, meta->dmaaddr, skb->len)) {
+			ring->current_slot = old_top_slot;
+			ring->used_slots = old_used_slots;
 			err = -EIO;
 			goto out_free_bounce;
 		}
@@ -1164,16 +1232,22 @@ static int dma_tx_fragment(struct b43_dmaring *ring,
 
 	ops->fill_descriptor(ring, desc, meta->dmaaddr, skb->len, 0, 1, 1);
 
+	if (ctl->flags & IEEE80211_TXCTL_SEND_AFTER_DTIM) {
+		/* Tell the firmware about the cookie of the last
+		 * mcast frame, so it can clear the more-data bit in it. */
+		b43_shm_write16(ring->dev, B43_SHM_SHARED,
+				B43_SHM_SH_MCASTCOOKIE, cookie);
+	}
 	/* Now transfer the whole frame. */
 	wmb();
 	ops->poke_tx(ring, next_slot(ring, slot));
 	return 0;
 
-      out_free_bounce:
+out_free_bounce:
 	dev_kfree_skb_any(skb);
-      out_unmap_hdr:
+out_unmap_hdr:
 	unmap_descbuffer(ring, meta_hdr->dmaaddr,
-			 sizeof(struct b43_txhdr_fw4), 1);
+			 hdrsize, 1);
 	return err;
 }
 
@@ -1202,10 +1276,27 @@ int b43_dma_tx(struct b43_wldev *dev,
 	       struct sk_buff *skb, struct ieee80211_tx_control *ctl)
 {
 	struct b43_dmaring *ring;
+	struct ieee80211_hdr *hdr;
 	int err = 0;
 	unsigned long flags;
 
-	ring = priority_to_txring(dev, ctl->queue);
+	if (unlikely(skb->len < 2 + 2 + 6)) {
+		/* Too short, this can't be a valid frame. */
+		return -EINVAL;
+	}
+
+	hdr = (struct ieee80211_hdr *)skb->data;
+	if (ctl->flags & IEEE80211_TXCTL_SEND_AFTER_DTIM) {
+		/* The multicast ring will be sent after the DTIM */
+		ring = dev->dma.tx_ring4;
+		/* Set the more-data bit. Ucode will clear it on
+		 * the last frame for us. */
+		hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_MOREDATA);
+	} else {
+		/* Decide by priority where to put this frame. */
+		ring = priority_to_txring(dev, ctl->queue);
+	}
+
 	spin_lock_irqsave(&ring->lock, flags);
 	B43_WARN_ON(!ring->tx);
 	if (unlikely(free_slots(ring) < SLOTS_PER_PACKET)) {
@@ -1219,6 +1310,13 @@ int b43_dma_tx(struct b43_wldev *dev,
 	B43_WARN_ON(ring->stopped);
 
 	err = dma_tx_fragment(ring, skb, ctl);
+	if (unlikely(err == -ENOKEY)) {
+		/* Drop this packet, as we don't have the encryption key
+		 * anymore and must not transmit it unencrypted. */
+		dev_kfree_skb_any(skb);
+		err = 0;
+		goto out_unlock;
+	}
 	if (unlikely(err)) {
 		b43err(dev->wl, "DMA tx mapping failure\n");
 		goto out_unlock;
@@ -1233,7 +1331,7 @@ int b43_dma_tx(struct b43_wldev *dev,
 			b43dbg(dev->wl, "Stopped TX ring %d\n", ring->index);
 		}
 	}
-      out_unlock:
+out_unlock:
 	spin_unlock_irqrestore(&ring->lock, flags);
 
 	return err;
@@ -1265,7 +1363,7 @@ void b43_dma_handle_txstatus(struct b43_wldev *dev,
 					 1);
 		else
 			unmap_descbuffer(ring, meta->dmaaddr,
-					 sizeof(struct b43_txhdr_fw4), 1);
+					 b43_txhdr_size(dev), 1);
 
 		if (meta->is_last_fragment) {
 			B43_WARN_ON(!meta->skb);
diff --git a/package/b43/src/dma.h b/package/b43/src/dma.h
index 3eed185be7..c0d6b69e65 100644
--- a/package/b43/src/dma.h
+++ b/package/b43/src/dma.h
@@ -170,8 +170,6 @@ struct b43_dmadesc_generic {
 #define B43_DMA0_RX_BUFFERSIZE	(2304 + 100)
 #define B43_DMA3_RX_BUFFERSIZE	16
 
-#ifdef CONFIG_B43_DMA
-
 struct sk_buff;
 struct b43_private;
 struct b43_txstatus;
@@ -205,6 +203,12 @@ struct b43_dma_ops {
 	void (*set_current_rxslot) (struct b43_dmaring * ring, int slot);
 };
 
+enum b43_dmatype {
+	B43_DMA_30BIT	= 30,
+	B43_DMA_32BIT	= 32,
+	B43_DMA_64BIT	= 64,
+};
+
 struct b43_dmaring {
 	/* Lowlevel DMA ops. */
 	const struct b43_dma_ops *ops;
@@ -237,8 +241,8 @@ struct b43_dmaring {
 	int index;
 	/* Boolean. Is this a TX ring? */
 	bool tx;
-	/* Boolean. 64bit DMA if true, 32bit DMA otherwise. */
-	bool dma64;
+	/* The type of DMA engine used. */
+	enum b43_dmatype type;
 	/* Boolean. Is this ring stopped at ieee80211 level? */
 	bool stopped;
 	/* Lock, only used for TX. */
@@ -257,8 +261,7 @@ static inline u32 b43_dma_read(struct b43_dmaring *ring, u16 offset)
 	return b43_read32(ring->dev, ring->mmio_base + offset);
 }
 
-static inline
-    void b43_dma_write(struct b43_dmaring *ring, u16 offset, u32 value)
+static inline void b43_dma_write(struct b43_dmaring *ring, u16 offset, u32 value)
 {
 	b43_write32(ring->dev, ring->mmio_base + offset, value);
 }
@@ -266,13 +269,6 @@ static inline
 int b43_dma_init(struct b43_wldev *dev);
 void b43_dma_free(struct b43_wldev *dev);
 
-int b43_dmacontroller_rx_reset(struct b43_wldev *dev,
-			       u16 dmacontroller_mmio_base, int dma64);
-int b43_dmacontroller_tx_reset(struct b43_wldev *dev,
-			       u16 dmacontroller_mmio_base, int dma64);
-
-u16 b43_dmacontroller_base(int dma64bit, int dmacontroller_idx);
-
 void b43_dma_tx_suspend(struct b43_wldev *dev);
 void b43_dma_tx_resume(struct b43_wldev *dev);
 
@@ -286,52 +282,4 @@ void b43_dma_handle_txstatus(struct b43_wldev *dev,
 
 void b43_dma_rx(struct b43_dmaring *ring);
 
-#else /* CONFIG_B43_DMA */
-
-static inline int b43_dma_init(struct b43_wldev *dev)
-{
-	return 0;
-}
-static inline void b43_dma_free(struct b43_wldev *dev)
-{
-}
-static inline
-    int b43_dmacontroller_rx_reset(struct b43_wldev *dev,
-				   u16 dmacontroller_mmio_base, int dma64)
-{
-	return 0;
-}
-static inline
-    int b43_dmacontroller_tx_reset(struct b43_wldev *dev,
-				   u16 dmacontroller_mmio_base, int dma64)
-{
-	return 0;
-}
-static inline
-    void b43_dma_get_tx_stats(struct b43_wldev *dev,
-			      struct ieee80211_tx_queue_stats *stats)
-{
-}
-static inline
-    int b43_dma_tx(struct b43_wldev *dev,
-		   struct sk_buff *skb, struct ieee80211_tx_control *ctl)
-{
-	return 0;
-}
-static inline
-    void b43_dma_handle_txstatus(struct b43_wldev *dev,
-				 const struct b43_txstatus *status)
-{
-}
-static inline void b43_dma_rx(struct b43_dmaring *ring)
-{
-}
-static inline void b43_dma_tx_suspend(struct b43_wldev *dev)
-{
-}
-static inline void b43_dma_tx_resume(struct b43_wldev *dev)
-{
-}
-
-#endif /* CONFIG_B43_DMA */
 #endif /* B43_DMA_H_ */
diff --git a/package/b43/src/leds.c b/package/b43/src/leds.c
index 19e588582c..4b590d8c65 100644
--- a/package/b43/src/leds.c
+++ b/package/b43/src/leds.c
@@ -4,7 +4,7 @@
   LED control
 
   Copyright (c) 2005 Martin Langer <martin-langer@gmx.de>,
-  Copyright (c) 2005 Stefano Brivio <st3@riseup.net>
+  Copyright (c) 2005 Stefano Brivio <stefano.brivio@polimi.it>
   Copyright (c) 2005-2007 Michael Buesch <mb@bu3sch.de>
   Copyright (c) 2005 Danny van Dyk <kugelfang@gentoo.org>
   Copyright (c) 2005 Andreas Jaggi <andreas.jaggi@waterwave.ch>
@@ -163,6 +163,9 @@ static void b43_map_led(struct b43_wldev *dev,
 		b43_register_led(dev, &dev->led_radio, name,
 				 b43_rfkill_led_name(dev),
 				 led_index, activelow);
+		/* Sync the RF-kill LED state with the switch state. */
+		if (dev->radio_hw_enable)
+			b43_led_turn_on(dev, led_index, activelow);
 		break;
 	case B43_LED_WEIRD:
 	case B43_LED_ASSOC:
@@ -187,10 +190,10 @@ void b43_leds_init(struct b43_wldev *dev)
 	enum b43_led_behaviour behaviour;
 	bool activelow;
 
-	sprom[0] = bus->sprom.r1.gpio0;
-	sprom[1] = bus->sprom.r1.gpio1;
-	sprom[2] = bus->sprom.r1.gpio2;
-	sprom[3] = bus->sprom.r1.gpio3;
+	sprom[0] = bus->sprom.gpio0;
+	sprom[1] = bus->sprom.gpio1;
+	sprom[2] = bus->sprom.gpio2;
+	sprom[3] = bus->sprom.gpio3;
 
 	for (i = 0; i < 4; i++) {
 		if (sprom[i] == 0xFF) {
@@ -232,4 +235,5 @@ void b43_leds_exit(struct b43_wldev *dev)
 	b43_unregister_led(&dev->led_tx);
 	b43_unregister_led(&dev->led_rx);
 	b43_unregister_led(&dev->led_assoc);
+	b43_unregister_led(&dev->led_radio);
 }
diff --git a/package/b43/src/lo.c b/package/b43/src/lo.c
index b14a1753a0..d890f366a2 100644
--- a/package/b43/src/lo.c
+++ b/package/b43/src/lo.c
@@ -5,7 +5,7 @@
   G PHY LO (LocalOscillator) Measuring and Control routines
 
   Copyright (c) 2005 Martin Langer <martin-langer@gmx.de>,
-  Copyright (c) 2005, 2006 Stefano Brivio <st3@riseup.net>
+  Copyright (c) 2005, 2006 Stefano Brivio <stefano.brivio@polimi.it>
   Copyright (c) 2005-2007 Michael Buesch <mb@bu3sch.de>
   Copyright (c) 2005, 2006 Danny van Dyk <kugelfang@gentoo.org>
   Copyright (c) 2005, 2006 Andreas Jaggi <andreas.jaggi@waterwave.ch>
@@ -264,8 +264,8 @@ static u16 lo_measure_feedthrough(struct b43_wldev *dev,
 		rfover |= pga;
 		rfover |= lna;
 		rfover |= trsw_rx;
-		if ((dev->dev->bus->sprom.r1.boardflags_lo & B43_BFL_EXTLNA) &&
-		    phy->rev > 6)
+		if ((dev->dev->bus->sprom.boardflags_lo & B43_BFL_EXTLNA)
+		    && phy->rev > 6)
 			rfover |= B43_PHY_RFOVERVAL_EXTLNA;
 
 		b43_phy_write(dev, B43_PHY_PGACTL, 0xE300);
@@ -555,20 +555,20 @@ struct lo_g_saved_values {
 	u16 phy_extg_01;
 	u16 phy_dacctl_hwpctl;
 	u16 phy_dacctl;
-	u16 phy_base_14;
+	u16 phy_cck_14;
 	u16 phy_hpwr_tssictl;
 	u16 phy_analogover;
 	u16 phy_analogoverval;
 	u16 phy_rfover;
 	u16 phy_rfoverval;
 	u16 phy_classctl;
-	u16 phy_base_3E;
+	u16 phy_cck_3E;
 	u16 phy_crs0;
 	u16 phy_pgactl;
-	u16 phy_base_2A;
+	u16 phy_cck_2A;
 	u16 phy_syncctl;
-	u16 phy_base_30;
-	u16 phy_base_06;
+	u16 phy_cck_30;
+	u16 phy_cck_06;
 
 	/* Radio registers */
 	u16 radio_43;
@@ -588,7 +588,7 @@ static void lo_measure_setup(struct b43_wldev *dev,
 		sav->phy_lo_mask = b43_phy_read(dev, B43_PHY_LO_MASK);
 		sav->phy_extg_01 = b43_phy_read(dev, B43_PHY_EXTG(0x01));
 		sav->phy_dacctl_hwpctl = b43_phy_read(dev, B43_PHY_DACCTL);
-		sav->phy_base_14 = b43_phy_read(dev, B43_PHY_BASE(0x14));
+		sav->phy_cck_14 = b43_phy_read(dev, B43_PHY_CCK(0x14));
 		sav->phy_hpwr_tssictl = b43_phy_read(dev, B43_PHY_HPWR_TSSICTL);
 
 		b43_phy_write(dev, B43_PHY_HPWR_TSSICTL,
@@ -600,14 +600,14 @@ static void lo_measure_setup(struct b43_wldev *dev,
 		b43_phy_write(dev, B43_PHY_DACCTL,
 			      b43_phy_read(dev, B43_PHY_DACCTL)
 			      | 0x40);
-		b43_phy_write(dev, B43_PHY_BASE(0x14),
-			      b43_phy_read(dev, B43_PHY_BASE(0x14))
+		b43_phy_write(dev, B43_PHY_CCK(0x14),
+			      b43_phy_read(dev, B43_PHY_CCK(0x14))
 			      | 0x200);
 	}
 	if (phy->type == B43_PHYTYPE_B &&
 	    phy->radio_ver == 0x2050 && phy->radio_rev < 6) {
-		b43_phy_write(dev, B43_PHY_BASE(0x16), 0x410);
-		b43_phy_write(dev, B43_PHY_BASE(0x17), 0x820);
+		b43_phy_write(dev, B43_PHY_CCK(0x16), 0x410);
+		b43_phy_write(dev, B43_PHY_CCK(0x17), 0x820);
 	}
 	if (!lo->rebuild && b43_has_hardware_pctl(phy))
 		lo_read_power_vector(dev);
@@ -618,7 +618,7 @@ static void lo_measure_setup(struct b43_wldev *dev,
 		sav->phy_rfover = b43_phy_read(dev, B43_PHY_RFOVER);
 		sav->phy_rfoverval = b43_phy_read(dev, B43_PHY_RFOVERVAL);
 		sav->phy_classctl = b43_phy_read(dev, B43_PHY_CLASSCTL);
-		sav->phy_base_3E = b43_phy_read(dev, B43_PHY_BASE(0x3E));
+		sav->phy_cck_3E = b43_phy_read(dev, B43_PHY_CCK(0x3E));
 		sav->phy_crs0 = b43_phy_read(dev, B43_PHY_CRS0);
 
 		b43_phy_write(dev, B43_PHY_CLASSCTL,
@@ -634,7 +634,7 @@ static void lo_measure_setup(struct b43_wldev *dev,
 			      & 0xFFFC);
 		if (phy->type == B43_PHYTYPE_G) {
 			if ((phy->rev >= 7) &&
-			    (sprom->r1.boardflags_lo & B43_BFL_EXTLNA)) {
+			    (sprom->boardflags_lo & B43_BFL_EXTLNA)) {
 				b43_phy_write(dev, B43_PHY_RFOVER, 0x933);
 			} else {
 				b43_phy_write(dev, B43_PHY_RFOVER, 0x133);
@@ -642,14 +642,14 @@ static void lo_measure_setup(struct b43_wldev *dev,
 		} else {
 			b43_phy_write(dev, B43_PHY_RFOVER, 0);
 		}
-		b43_phy_write(dev, B43_PHY_BASE(0x3E), 0);
+		b43_phy_write(dev, B43_PHY_CCK(0x3E), 0);
 	}
 	sav->reg_3F4 = b43_read16(dev, 0x3F4);
 	sav->reg_3E2 = b43_read16(dev, 0x3E2);
 	sav->radio_43 = b43_radio_read16(dev, 0x43);
 	sav->radio_7A = b43_radio_read16(dev, 0x7A);
 	sav->phy_pgactl = b43_phy_read(dev, B43_PHY_PGACTL);
-	sav->phy_base_2A = b43_phy_read(dev, B43_PHY_BASE(0x2A));
+	sav->phy_cck_2A = b43_phy_read(dev, B43_PHY_CCK(0x2A));
 	sav->phy_syncctl = b43_phy_read(dev, B43_PHY_SYNCCTL);
 	sav->phy_dacctl = b43_phy_read(dev, B43_PHY_DACCTL);
 
@@ -658,10 +658,10 @@ static void lo_measure_setup(struct b43_wldev *dev,
 		sav->radio_52 &= 0x00F0;
 	}
 	if (phy->type == B43_PHYTYPE_B) {
-		sav->phy_base_30 = b43_phy_read(dev, B43_PHY_BASE(0x30));
-		sav->phy_base_06 = b43_phy_read(dev, B43_PHY_BASE(0x06));
-		b43_phy_write(dev, B43_PHY_BASE(0x30), 0x00FF);
-		b43_phy_write(dev, B43_PHY_BASE(0x06), 0x3F3F);
+		sav->phy_cck_30 = b43_phy_read(dev, B43_PHY_CCK(0x30));
+		sav->phy_cck_06 = b43_phy_read(dev, B43_PHY_CCK(0x06));
+		b43_phy_write(dev, B43_PHY_CCK(0x30), 0x00FF);
+		b43_phy_write(dev, B43_PHY_CCK(0x06), 0x3F3F);
 	} else {
 		b43_write16(dev, 0x3E2, b43_read16(dev, 0x3E2)
 			    | 0x8000);
@@ -670,7 +670,7 @@ static void lo_measure_setup(struct b43_wldev *dev,
 		    & 0xF000);
 
 	tmp =
-	    (phy->type == B43_PHYTYPE_G) ? B43_PHY_LO_MASK : B43_PHY_BASE(0x2E);
+	    (phy->type == B43_PHYTYPE_G) ? B43_PHY_LO_MASK : B43_PHY_CCK(0x2E);
 	b43_phy_write(dev, tmp, 0x007F);
 
 	tmp = sav->phy_syncctl;
@@ -678,26 +678,26 @@ static void lo_measure_setup(struct b43_wldev *dev,
 	tmp = sav->radio_7A;
 	b43_radio_write16(dev, 0x007A, tmp & 0xFFF0);
 
-	b43_phy_write(dev, B43_PHY_BASE(0x2A), 0x8A3);
+	b43_phy_write(dev, B43_PHY_CCK(0x2A), 0x8A3);
 	if (phy->type == B43_PHYTYPE_G ||
 	    (phy->type == B43_PHYTYPE_B &&
 	     phy->radio_ver == 0x2050 && phy->radio_rev >= 6)) {
-		b43_phy_write(dev, B43_PHY_BASE(0x2B), 0x1003);
+		b43_phy_write(dev, B43_PHY_CCK(0x2B), 0x1003);
 	} else
-		b43_phy_write(dev, B43_PHY_BASE(0x2B), 0x0802);
+		b43_phy_write(dev, B43_PHY_CCK(0x2B), 0x0802);
 	if (phy->rev >= 2)
 		b43_dummy_transmission(dev);
 	b43_radio_selectchannel(dev, 6, 0);
 	b43_radio_read16(dev, 0x51);	/* dummy read */
 	if (phy->type == B43_PHYTYPE_G)
-		b43_phy_write(dev, B43_PHY_BASE(0x2F), 0);
+		b43_phy_write(dev, B43_PHY_CCK(0x2F), 0);
 	if (lo->rebuild)
 		lo_measure_txctl_values(dev);
 	if (phy->type == B43_PHYTYPE_G && phy->rev >= 3) {
 		b43_phy_write(dev, B43_PHY_LO_MASK, 0xC078);
 	} else {
 		if (phy->type == B43_PHYTYPE_B)
-			b43_phy_write(dev, B43_PHY_BASE(0x2E), 0x8078);
+			b43_phy_write(dev, B43_PHY_CCK(0x2E), 0x8078);
 		else
 			b43_phy_write(dev, B43_PHY_LO_MASK, 0x8078);
 	}
@@ -732,17 +732,17 @@ static void lo_measure_restore(struct b43_wldev *dev,
 	}
 	if (phy->type == B43_PHYTYPE_G) {
 		if (phy->rev >= 3)
-			b43_phy_write(dev, B43_PHY_BASE(0x2E), 0xC078);
+			b43_phy_write(dev, B43_PHY_CCK(0x2E), 0xC078);
 		else
-			b43_phy_write(dev, B43_PHY_BASE(0x2E), 0x8078);
+			b43_phy_write(dev, B43_PHY_CCK(0x2E), 0x8078);
 		if (phy->rev >= 2)
-			b43_phy_write(dev, B43_PHY_BASE(0x2F), 0x0202);
+			b43_phy_write(dev, B43_PHY_CCK(0x2F), 0x0202);
 		else
-			b43_phy_write(dev, B43_PHY_BASE(0x2F), 0x0101);
+			b43_phy_write(dev, B43_PHY_CCK(0x2F), 0x0101);
 	}
 	b43_write16(dev, 0x3F4, sav->reg_3F4);
 	b43_phy_write(dev, B43_PHY_PGACTL, sav->phy_pgactl);
-	b43_phy_write(dev, B43_PHY_BASE(0x2A), sav->phy_base_2A);
+	b43_phy_write(dev, B43_PHY_CCK(0x2A), sav->phy_cck_2A);
 	b43_phy_write(dev, B43_PHY_SYNCCTL, sav->phy_syncctl);
 	b43_phy_write(dev, B43_PHY_DACCTL, sav->phy_dacctl);
 	b43_radio_write16(dev, 0x43, sav->radio_43);
@@ -755,8 +755,8 @@ static void lo_measure_restore(struct b43_wldev *dev,
 	b43_write16(dev, 0x3E2, sav->reg_3E2);
 	if (phy->type == B43_PHYTYPE_B &&
 	    phy->radio_ver == 0x2050 && phy->radio_rev <= 5) {
-		b43_phy_write(dev, B43_PHY_BASE(0x30), sav->phy_base_30);
-		b43_phy_write(dev, B43_PHY_BASE(0x06), sav->phy_base_06);
+		b43_phy_write(dev, B43_PHY_CCK(0x30), sav->phy_cck_30);
+		b43_phy_write(dev, B43_PHY_CCK(0x06), sav->phy_cck_06);
 	}
 	if (phy->rev >= 2) {
 		b43_phy_write(dev, B43_PHY_ANALOGOVER, sav->phy_analogover);
@@ -765,7 +765,7 @@ static void lo_measure_restore(struct b43_wldev *dev,
 		b43_phy_write(dev, B43_PHY_CLASSCTL, sav->phy_classctl);
 		b43_phy_write(dev, B43_PHY_RFOVER, sav->phy_rfover);
 		b43_phy_write(dev, B43_PHY_RFOVERVAL, sav->phy_rfoverval);
-		b43_phy_write(dev, B43_PHY_BASE(0x3E), sav->phy_base_3E);
+		b43_phy_write(dev, B43_PHY_CCK(0x3E), sav->phy_cck_3E);
 		b43_phy_write(dev, B43_PHY_CRS0, sav->phy_crs0);
 	}
 	if (b43_has_hardware_pctl(phy)) {
@@ -773,7 +773,7 @@ static void lo_measure_restore(struct b43_wldev *dev,
 		b43_phy_write(dev, B43_PHY_LO_MASK, tmp);
 		b43_phy_write(dev, B43_PHY_EXTG(0x01), sav->phy_extg_01);
 		b43_phy_write(dev, B43_PHY_DACCTL, sav->phy_dacctl_hwpctl);
-		b43_phy_write(dev, B43_PHY_BASE(0x14), sav->phy_base_14);
+		b43_phy_write(dev, B43_PHY_CCK(0x14), sav->phy_cck_14);
 		b43_phy_write(dev, B43_PHY_HPWR_TSSICTL, sav->phy_hpwr_tssictl);
 	}
 	b43_radio_selectchannel(dev, sav->old_channel, 1);
diff --git a/package/b43/src/main.c b/package/b43/src/main.c
index 9f8175c25a..afb109447a 100644
--- a/package/b43/src/main.c
+++ b/package/b43/src/main.c
@@ -3,7 +3,7 @@
   Broadcom B43 wireless driver
 
   Copyright (c) 2005 Martin Langer <martin-langer@gmx.de>
-  Copyright (c) 2005 Stefano Brivio <st3@riseup.net>
+  Copyright (c) 2005 Stefano Brivio <stefano.brivio@polimi.it>
   Copyright (c) 2005, 2006 Michael Buesch <mb@bu3sch.de>
   Copyright (c) 2005 Danny van Dyk <kugelfang@gentoo.org>
   Copyright (c) 2005 Andreas Jaggi <andreas.jaggi@waterwave.ch>
@@ -46,7 +46,6 @@
 #include "debugfs.h"
 #include "phy.h"
 #include "dma.h"
-#include "pio.h"
 #include "sysfs.h"
 #include "xmit.h"
 #include "lo.h"
@@ -58,31 +57,12 @@ MODULE_AUTHOR("Stefano Brivio");
 MODULE_AUTHOR("Michael Buesch");
 MODULE_LICENSE("GPL");
 
-extern char *nvram_get(char *name);
-
-#if defined(CONFIG_B43_DMA) && defined(CONFIG_B43_PIO)
-static int modparam_pio;
-module_param_named(pio, modparam_pio, int, 0444);
-MODULE_PARM_DESC(pio, "enable(1) / disable(0) PIO mode");
-#elif defined(CONFIG_B43_DMA)
-# define modparam_pio	0
-#elif defined(CONFIG_B43_PIO)
-# define modparam_pio	1
-#endif
 
 static int modparam_bad_frames_preempt;
 module_param_named(bad_frames_preempt, modparam_bad_frames_preempt, int, 0444);
 MODULE_PARM_DESC(bad_frames_preempt,
 		 "enable(1) / disable(0) Bad Frames Preemption");
 
-static int modparam_short_retry = B43_DEFAULT_SHORT_RETRY_LIMIT;
-module_param_named(short_retry, modparam_short_retry, int, 0444);
-MODULE_PARM_DESC(short_retry, "Short-Retry-Limit (0 - 15)");
-
-static int modparam_long_retry = B43_DEFAULT_LONG_RETRY_LIMIT;
-module_param_named(long_retry, modparam_long_retry, int, 0444);
-MODULE_PARM_DESC(long_retry, "Long-Retry-Limit (0 - 15)");
-
 static char modparam_fwpostfix[16];
 module_param_string(fwpostfix, modparam_fwpostfix, 16, 0444);
 MODULE_PARM_DESC(fwpostfix, "Postfix for the .fw files to load.");
@@ -101,52 +81,41 @@ static const struct ssb_device_id b43_ssb_tbl[] = {
 	SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_80211, 7),
 	SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_80211, 9),
 	SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_80211, 10),
+	SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_80211, 11),
+	SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_80211, 13),
 	SSB_DEVTABLE_END
 };
 
 MODULE_DEVICE_TABLE(ssb, b43_ssb_tbl);
 
-static const struct pci_device_id b43_pci_bridge_tbl[] = {
-	{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4311) },
-	{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4312) },
-	{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4318) },
-	{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4319) },
-	{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4320) },
-	{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4321) },
-	{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4324) },
-	{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4325) },
-	{ 0, },
-};
-MODULE_DEVICE_TABLE(pci, b43_pci_bridge_tbl);
-
-static struct pci_driver b43_pci_bridge_driver = {
-	.name = "b43-pci-bridge",
-	.id_table = b43_pci_bridge_tbl,
-};
 /* Channel and ratetables are shared for all devices.
  * They can't be const, because ieee80211 puts some precalculated
  * data in there. This data is the same for all devices, so we don't
  * get concurrency issues */
 #define RATETAB_ENT(_rateid, _flags) \
-	{							\
-		.rate	= B43_RATE_TO_BASE100KBPS(_rateid),	\
-		.val	= (_rateid),				\
-		.val2	= (_rateid),				\
-		.flags	= (_flags),				\
+	{								\
+		.bitrate	= B43_RATE_TO_BASE100KBPS(_rateid),	\
+		.hw_value	= (_rateid),				\
+		.flags		= (_flags),				\
 	}
+
+/*
+ * NOTE: When changing this, sync with xmit.c's
+ *	 b43_plcp_get_bitrate_idx_* functions!
+ */
 static struct ieee80211_rate __b43_ratetable[] = {
-	RATETAB_ENT(B43_CCK_RATE_1MB, IEEE80211_RATE_CCK),
-	RATETAB_ENT(B43_CCK_RATE_2MB, IEEE80211_RATE_CCK_2),
-	RATETAB_ENT(B43_CCK_RATE_5MB, IEEE80211_RATE_CCK_2),
-	RATETAB_ENT(B43_CCK_RATE_11MB, IEEE80211_RATE_CCK_2),
-	RATETAB_ENT(B43_OFDM_RATE_6MB, IEEE80211_RATE_OFDM),
-	RATETAB_ENT(B43_OFDM_RATE_9MB, IEEE80211_RATE_OFDM),
-	RATETAB_ENT(B43_OFDM_RATE_12MB, IEEE80211_RATE_OFDM),
-	RATETAB_ENT(B43_OFDM_RATE_18MB, IEEE80211_RATE_OFDM),
-	RATETAB_ENT(B43_OFDM_RATE_24MB, IEEE80211_RATE_OFDM),
-	RATETAB_ENT(B43_OFDM_RATE_36MB, IEEE80211_RATE_OFDM),
-	RATETAB_ENT(B43_OFDM_RATE_48MB, IEEE80211_RATE_OFDM),
-	RATETAB_ENT(B43_OFDM_RATE_54MB, IEEE80211_RATE_OFDM),
+	RATETAB_ENT(B43_CCK_RATE_1MB, 0),
+	RATETAB_ENT(B43_CCK_RATE_2MB, IEEE80211_RATE_SHORT_PREAMBLE),
+	RATETAB_ENT(B43_CCK_RATE_5MB, IEEE80211_RATE_SHORT_PREAMBLE),
+	RATETAB_ENT(B43_CCK_RATE_11MB, IEEE80211_RATE_SHORT_PREAMBLE),
+	RATETAB_ENT(B43_OFDM_RATE_6MB, 0),
+	RATETAB_ENT(B43_OFDM_RATE_9MB, 0),
+	RATETAB_ENT(B43_OFDM_RATE_12MB, 0),
+	RATETAB_ENT(B43_OFDM_RATE_18MB, 0),
+	RATETAB_ENT(B43_OFDM_RATE_24MB, 0),
+	RATETAB_ENT(B43_OFDM_RATE_36MB, 0),
+	RATETAB_ENT(B43_OFDM_RATE_48MB, 0),
+	RATETAB_ENT(B43_OFDM_RATE_54MB, 0),
 };
 
 #define b43_a_ratetable		(__b43_ratetable + 4)
@@ -158,16 +127,10 @@ static struct ieee80211_rate __b43_ratetable[] = {
 
 #define CHANTAB_ENT(_chanid, _freq) \
 	{							\
-		.chan	= (_chanid),				\
-		.freq	= (_freq),				\
-		.val	= (_chanid),				\
-		.flag	= IEEE80211_CHAN_W_SCAN |		\
-			  IEEE80211_CHAN_W_ACTIVE_SCAN |	\
-			  IEEE80211_CHAN_W_IBSS,		\
-		.power_level	= 0xFF,				\
-		.antenna_max	= 0xFF,				\
+		.center_freq	= (_freq),			\
+		.hw_value	= (_chanid),			\
 	}
-static struct ieee80211_channel b43_bg_chantable[] = {
+static struct ieee80211_channel b43_2ghz_chantable[] = {
 	CHANTAB_ENT(1, 2412),
 	CHANTAB_ENT(2, 2417),
 	CHANTAB_ENT(3, 2422),
@@ -184,8 +147,8 @@ static struct ieee80211_channel b43_bg_chantable[] = {
 	CHANTAB_ENT(14, 2484),
 };
 
-#define b43_bg_chantable_size	ARRAY_SIZE(b43_bg_chantable)
-static struct ieee80211_channel b43_a_chantable[] = {
+#ifdef NOTYET
+static struct ieee80211_channel b43_5ghz_chantable[] = {
 	CHANTAB_ENT(36, 5180),
 	CHANTAB_ENT(40, 5200),
 	CHANTAB_ENT(44, 5220),
@@ -201,7 +164,20 @@ static struct ieee80211_channel b43_a_chantable[] = {
 	CHANTAB_ENT(165, 5825),
 };
 
-#define b43_a_chantable_size	ARRAY_SIZE(b43_a_chantable)
+static struct ieee80211_supported_band b43_band_5GHz = {
+	.channels = b43_5ghz_chantable,
+	.n_channels = ARRAY_SIZE(b43_5ghz_chantable),
+	.bitrates = b43_a_ratetable,
+	.n_bitrates = b43_a_ratetable_size,
+};
+#endif
+
+static struct ieee80211_supported_band b43_band_2GHz = {
+	.channels = b43_2ghz_chantable,
+	.n_channels = ARRAY_SIZE(b43_2ghz_chantable),
+	.bitrates = b43_g_ratetable,
+	.n_bitrates = b43_g_ratetable_size,
+};
 
 static void b43_wireless_core_exit(struct b43_wldev *dev);
 static int b43_wireless_core_init(struct b43_wldev *dev);
@@ -286,13 +262,12 @@ static void b43_ram_write(struct b43_wldev *dev, u16 offset, u32 val)
 	b43_write32(dev, B43_MMIO_RAM_DATA, val);
 }
 
-static inline
-    void b43_shm_control_word(struct b43_wldev *dev, u16 routing, u16 offset)
+static inline void b43_shm_control_word(struct b43_wldev *dev,
+					u16 routing, u16 offset)
 {
 	u32 control;
 
 	/* "offset" is the WORD offset. */
-
 	control = routing;
 	control <<= 16;
 	control |= offset;
@@ -301,8 +276,11 @@ static inline
 
 u32 b43_shm_read32(struct b43_wldev *dev, u16 routing, u16 offset)
 {
+	struct b43_wl *wl = dev->wl;
+	unsigned long flags;
 	u32 ret;
 
+	spin_lock_irqsave(&wl->shm_lock, flags);
 	if (routing == B43_SHM_SHARED) {
 		B43_WARN_ON(offset & 0x0001);
 		if (offset & 0x0003) {
@@ -313,20 +291,25 @@ u32 b43_shm_read32(struct b43_wldev *dev, u16 routing, u16 offset)
 			b43_shm_control_word(dev, routing, (offset >> 2) + 1);
 			ret |= b43_read16(dev, B43_MMIO_SHM_DATA);
 
-			return ret;
+			goto out;
 		}
 		offset >>= 2;
 	}
 	b43_shm_control_word(dev, routing, offset);
 	ret = b43_read32(dev, B43_MMIO_SHM_DATA);
+out:
+	spin_unlock_irqrestore(&wl->shm_lock, flags);
 
 	return ret;
 }
 
 u16 b43_shm_read16(struct b43_wldev * dev, u16 routing, u16 offset)
 {
+	struct b43_wl *wl = dev->wl;
+	unsigned long flags;
 	u16 ret;
 
+	spin_lock_irqsave(&wl->shm_lock, flags);
 	if (routing == B43_SHM_SHARED) {
 		B43_WARN_ON(offset & 0x0001);
 		if (offset & 0x0003) {
@@ -334,55 +317,63 @@ u16 b43_shm_read16(struct b43_wldev * dev, u16 routing, u16 offset)
 			b43_shm_control_word(dev, routing, offset >> 2);
 			ret = b43_read16(dev, B43_MMIO_SHM_DATA_UNALIGNED);
 
-			return ret;
+			goto out;
 		}
 		offset >>= 2;
 	}
 	b43_shm_control_word(dev, routing, offset);
 	ret = b43_read16(dev, B43_MMIO_SHM_DATA);
+out:
+	spin_unlock_irqrestore(&wl->shm_lock, flags);
 
 	return ret;
 }
 
 void b43_shm_write32(struct b43_wldev *dev, u16 routing, u16 offset, u32 value)
 {
+	struct b43_wl *wl = dev->wl;
+	unsigned long flags;
+
+	spin_lock_irqsave(&wl->shm_lock, flags);
 	if (routing == B43_SHM_SHARED) {
 		B43_WARN_ON(offset & 0x0001);
 		if (offset & 0x0003) {
 			/* Unaligned access */
 			b43_shm_control_word(dev, routing, offset >> 2);
-			mmiowb();
 			b43_write16(dev, B43_MMIO_SHM_DATA_UNALIGNED,
 				    (value >> 16) & 0xffff);
-			mmiowb();
 			b43_shm_control_word(dev, routing, (offset >> 2) + 1);
-			mmiowb();
 			b43_write16(dev, B43_MMIO_SHM_DATA, value & 0xffff);
-			return;
+			goto out;
 		}
 		offset >>= 2;
 	}
 	b43_shm_control_word(dev, routing, offset);
-	mmiowb();
 	b43_write32(dev, B43_MMIO_SHM_DATA, value);
+out:
+	spin_unlock_irqrestore(&wl->shm_lock, flags);
 }
 
 void b43_shm_write16(struct b43_wldev *dev, u16 routing, u16 offset, u16 value)
 {
+	struct b43_wl *wl = dev->wl;
+	unsigned long flags;
+
+	spin_lock_irqsave(&wl->shm_lock, flags);
 	if (routing == B43_SHM_SHARED) {
 		B43_WARN_ON(offset & 0x0001);
 		if (offset & 0x0003) {
 			/* Unaligned access */
 			b43_shm_control_word(dev, routing, offset >> 2);
-			mmiowb();
 			b43_write16(dev, B43_MMIO_SHM_DATA_UNALIGNED, value);
-			return;
+			goto out;
 		}
 		offset >>= 2;
 	}
 	b43_shm_control_word(dev, routing, offset);
-	mmiowb();
 	b43_write16(dev, B43_MMIO_SHM_DATA, value);
+out:
+	spin_unlock_irqrestore(&wl->shm_lock, flags);
 }
 
 /* Read HostFlags */
@@ -1029,9 +1020,8 @@ static void b43_jssi_write(struct b43_wldev *dev, u32 jssi)
 static void b43_generate_noise_sample(struct b43_wldev *dev)
 {
 	b43_jssi_write(dev, 0x7F7F7F7F);
-	b43_write32(dev, B43_MMIO_STATUS2_BITFIELD,
-		    b43_read32(dev, B43_MMIO_STATUS2_BITFIELD)
-		    | (1 << 4));
+	b43_write32(dev, B43_MMIO_MACCMD,
+		    b43_read32(dev, B43_MMIO_MACCMD) | B43_MACCMD_BGNOISE);
 	B43_WARN_ON(dev->noisecalc.channel_at_start != dev->phy.channel);
 }
 
@@ -1117,18 +1107,18 @@ static void handle_irq_tbtt_indication(struct b43_wldev *dev)
 		if (1 /*FIXME: the last PSpoll frame was sent successfully */ )
 			b43_power_saving_ctl_bits(dev, 0);
 	}
-	dev->reg124_set_0x4 = 0;
 	if (b43_is_mode(dev->wl, IEEE80211_IF_TYPE_IBSS))
-		dev->reg124_set_0x4 = 1;
+		dev->dfq_valid = 1;
 }
 
 static void handle_irq_atim_end(struct b43_wldev *dev)
 {
-	if (!dev->reg124_set_0x4 /*FIXME rename this variable */ )
-		return;
-	b43_write32(dev, B43_MMIO_STATUS2_BITFIELD,
-		    b43_read32(dev, B43_MMIO_STATUS2_BITFIELD)
-		    | 0x4);
+	if (dev->dfq_valid) {
+		b43_write32(dev, B43_MMIO_MACCMD,
+			    b43_read32(dev, B43_MMIO_MACCMD)
+			    | B43_MACCMD_DFQ_VALID);
+		dev->dfq_valid = 0;
+	}
 }
 
 static void handle_irq_pmq(struct b43_wldev *dev)
@@ -1183,29 +1173,74 @@ static void b43_write_beacon_template(struct b43_wldev *dev,
 				      u16 ram_offset,
 				      u16 shm_size_offset, u8 rate)
 {
-	int len;
-	const u8 *data;
+	unsigned int i, len, variable_len;
+	const struct ieee80211_mgmt *bcn;
+	const u8 *ie;
+	bool tim_found = 0;
 
-	B43_WARN_ON(!dev->cached_beacon);
-	len = min((size_t) dev->cached_beacon->len,
+	bcn = (const struct ieee80211_mgmt *)(dev->wl->current_beacon->data);
+	len = min((size_t) dev->wl->current_beacon->len,
 		  0x200 - sizeof(struct b43_plcp_hdr6));
-	data = (const u8 *)(dev->cached_beacon->data);
-	b43_write_template_common(dev, data,
+
+	b43_write_template_common(dev, (const u8 *)bcn,
 				  len, ram_offset, shm_size_offset, rate);
+
+	/* Find the position of the TIM and the DTIM_period value
+	 * and write them to SHM. */
+	ie = bcn->u.beacon.variable;
+	variable_len = len - offsetof(struct ieee80211_mgmt, u.beacon.variable);
+	for (i = 0; i < variable_len - 2; ) {
+		uint8_t ie_id, ie_len;
+
+		ie_id = ie[i];
+		ie_len = ie[i + 1];
+		if (ie_id == 5) {
+			u16 tim_position;
+			u16 dtim_period;
+			/* This is the TIM Information Element */
+
+			/* Check whether the ie_len is in the beacon data range. */
+			if (variable_len < ie_len + 2 + i)
+				break;
+			/* A valid TIM is at least 4 bytes long. */
+			if (ie_len < 4)
+				break;
+			tim_found = 1;
+
+			tim_position = sizeof(struct b43_plcp_hdr6);
+			tim_position += offsetof(struct ieee80211_mgmt, u.beacon.variable);
+			tim_position += i;
+
+			dtim_period = ie[i + 3];
+
+			b43_shm_write16(dev, B43_SHM_SHARED,
+					B43_SHM_SH_TIMBPOS, tim_position);
+			b43_shm_write16(dev, B43_SHM_SHARED,
+					B43_SHM_SH_DTIMPER, dtim_period);
+			break;
+		}
+		i += ie_len + 2;
+	}
+	if (!tim_found) {
+		b43warn(dev->wl, "Did not find a valid TIM IE in "
+			"the beacon template packet. AP or IBSS operation "
+			"may be broken.\n");
+	}
 }
 
 static void b43_write_probe_resp_plcp(struct b43_wldev *dev,
-				      u16 shm_offset, u16 size, u8 rate)
+				      u16 shm_offset, u16 size,
+				      struct ieee80211_rate *rate)
 {
 	struct b43_plcp_hdr4 plcp;
 	u32 tmp;
 	__le16 dur;
 
 	plcp.data = 0;
-	b43_generate_plcp_hdr(&plcp, size + FCS_LEN, rate);
+	b43_generate_plcp_hdr(&plcp, size + FCS_LEN, rate->hw_value);
 	dur = ieee80211_generic_frame_duration(dev->wl->hw,
-					       dev->wl->if_id, size,
-					       B43_RATE_TO_BASE100KBPS(rate));
+					       dev->wl->vif, size,
+					       rate);
 	/* Write PLCP in two parts and timing for packet transfer */
 	tmp = le32_to_cpu(plcp.data);
 	b43_shm_write16(dev, B43_SHM_SHARED, shm_offset, tmp & 0xFFFF);
@@ -1219,40 +1254,44 @@ static void b43_write_probe_resp_plcp(struct b43_wldev *dev,
  * 2) Patching duration field
  * 3) Stripping TIM
  */
-static u8 *b43_generate_probe_resp(struct b43_wldev *dev,
-				   u16 * dest_size, u8 rate)
+static const u8 * b43_generate_probe_resp(struct b43_wldev *dev,
+					  u16 *dest_size,
+					  struct ieee80211_rate *rate)
 {
 	const u8 *src_data;
 	u8 *dest_data;
 	u16 src_size, elem_size, src_pos, dest_pos;
 	__le16 dur;
 	struct ieee80211_hdr *hdr;
+	size_t ie_start;
+
+	src_size = dev->wl->current_beacon->len;
+	src_data = (const u8 *)dev->wl->current_beacon->data;
 
-	B43_WARN_ON(!dev->cached_beacon);
-	src_size = dev->cached_beacon->len;
-	src_data = (const u8 *)dev->cached_beacon->data;
+	/* Get the start offset of the variable IEs in the packet. */
+	ie_start = offsetof(struct ieee80211_mgmt, u.probe_resp.variable);
+	B43_WARN_ON(ie_start != offsetof(struct ieee80211_mgmt, u.beacon.variable));
 
-	if (unlikely(src_size < 0x24)) {
-		b43dbg(dev->wl, "b43_generate_probe_resp: " "invalid beacon\n");
+	if (B43_WARN_ON(src_size < ie_start))
 		return NULL;
-	}
 
 	dest_data = kmalloc(src_size, GFP_ATOMIC);
 	if (unlikely(!dest_data))
 		return NULL;
 
-	/* 0x24 is offset of first variable-len Information-Element
-	 * in beacon frame.
-	 */
-	memcpy(dest_data, src_data, 0x24);
-	src_pos = dest_pos = 0x24;
-	for (; src_pos < src_size - 2; src_pos += elem_size) {
+	/* Copy the static data and all Information Elements, except the TIM. */
+	memcpy(dest_data, src_data, ie_start);
+	src_pos = ie_start;
+	dest_pos = ie_start;
+	for ( ; src_pos < src_size - 2; src_pos += elem_size) {
 		elem_size = src_data[src_pos + 1] + 2;
-		if (src_data[src_pos] != 0x05) {	/* TIM */
-			memcpy(dest_data + dest_pos, src_data + src_pos,
-			       elem_size);
-			dest_pos += elem_size;
+		if (src_data[src_pos] == 5) {
+			/* This is the TIM. */
+			continue;
 		}
+		memcpy(dest_data + dest_pos, src_data + src_pos,
+		       elem_size);
+		dest_pos += elem_size;
 	}
 	*dest_size = dest_pos;
 	hdr = (struct ieee80211_hdr *)dest_data;
@@ -1261,8 +1300,8 @@ static u8 *b43_generate_probe_resp(struct b43_wldev *dev,
 	hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
 					 IEEE80211_STYPE_PROBE_RESP);
 	dur = ieee80211_generic_frame_duration(dev->wl->hw,
-					       dev->wl->if_id, *dest_size,
-					       B43_RATE_TO_BASE100KBPS(rate));
+					       dev->wl->vif, *dest_size,
+					       rate);
 	hdr->duration_id = dur;
 
 	return dest_data;
@@ -1270,13 +1309,13 @@ static u8 *b43_generate_probe_resp(struct b43_wldev *dev,
 
 static void b43_write_probe_resp_template(struct b43_wldev *dev,
 					  u16 ram_offset,
-					  u16 shm_size_offset, u8 rate)
+					  u16 shm_size_offset,
+					  struct ieee80211_rate *rate)
 {
-	u8 *probe_resp_data;
+	const u8 *probe_resp_data;
 	u16 size;
 
-	B43_WARN_ON(!dev->cached_beacon);
-	size = dev->cached_beacon->len;
+	size = dev->wl->current_beacon->len;
 	probe_resp_data = b43_generate_probe_resp(dev, &size, rate);
 	if (unlikely(!probe_resp_data))
 		return;
@@ -1284,50 +1323,33 @@ static void b43_write_probe_resp_template(struct b43_wldev *dev,
 	/* Looks like PLCP headers plus packet timings are stored for
 	 * all possible basic rates
 	 */
-	b43_write_probe_resp_plcp(dev, 0x31A, size, B43_CCK_RATE_1MB);
-	b43_write_probe_resp_plcp(dev, 0x32C, size, B43_CCK_RATE_2MB);
-	b43_write_probe_resp_plcp(dev, 0x33E, size, B43_CCK_RATE_5MB);
-	b43_write_probe_resp_plcp(dev, 0x350, size, B43_CCK_RATE_11MB);
+	b43_write_probe_resp_plcp(dev, 0x31A, size, &b43_b_ratetable[0]);
+	b43_write_probe_resp_plcp(dev, 0x32C, size, &b43_b_ratetable[1]);
+	b43_write_probe_resp_plcp(dev, 0x33E, size, &b43_b_ratetable[2]);
+	b43_write_probe_resp_plcp(dev, 0x350, size, &b43_b_ratetable[3]);
 
 	size = min((size_t) size, 0x200 - sizeof(struct b43_plcp_hdr6));
 	b43_write_template_common(dev, probe_resp_data,
-				  size, ram_offset, shm_size_offset, rate);
+				  size, ram_offset, shm_size_offset,
+				  rate->hw_value);
 	kfree(probe_resp_data);
 }
 
-static int b43_refresh_cached_beacon(struct b43_wldev *dev,
-				     struct sk_buff *beacon)
-{
-	if (dev->cached_beacon)
-		kfree_skb(dev->cached_beacon);
-	dev->cached_beacon = beacon;
-
-	return 0;
-}
-
-static void b43_update_templates(struct b43_wldev *dev)
-{
-	u32 status;
-
-	B43_WARN_ON(!dev->cached_beacon);
-
-	b43_write_beacon_template(dev, 0x68, 0x18, B43_CCK_RATE_1MB);
-	b43_write_beacon_template(dev, 0x468, 0x1A, B43_CCK_RATE_1MB);
-	b43_write_probe_resp_template(dev, 0x268, 0x4A, B43_CCK_RATE_11MB);
-
-	status = b43_read32(dev, B43_MMIO_STATUS2_BITFIELD);
-	status |= 0x03;
-	b43_write32(dev, B43_MMIO_STATUS2_BITFIELD, status);
-}
-
-static void b43_refresh_templates(struct b43_wldev *dev, struct sk_buff *beacon)
+/* Asynchronously update the packet templates in template RAM.
+ * Locking: Requires wl->irq_lock to be locked. */
+static void b43_update_templates(struct b43_wl *wl, struct sk_buff *beacon)
 {
-	int err;
+	/* This is the top half of the ansynchronous beacon update.
+	 * The bottom half is the beacon IRQ.
+	 * Beacon update must be asynchronous to avoid sending an
+	 * invalid beacon. This can happen for example, if the firmware
+	 * transmits a beacon while we are updating it. */
 
-	err = b43_refresh_cached_beacon(dev, beacon);
-	if (unlikely(err))
-		return;
-	b43_update_templates(dev);
+	if (wl->current_beacon)
+		dev_kfree_skb_any(wl->current_beacon);
+	wl->current_beacon = beacon;
+	wl->beacon0_uploaded = 0;
+	wl->beacon1_uploaded = 0;
 }
 
 static void b43_set_ssid(struct b43_wldev *dev, const u8 * ssid, u8 ssid_len)
@@ -1363,33 +1385,34 @@ static void b43_set_beacon_int(struct b43_wldev *dev, u16 beacon_int)
 
 static void handle_irq_beacon(struct b43_wldev *dev)
 {
-	u32 status;
+	struct b43_wl *wl = dev->wl;
+	u32 cmd;
 
-	if (!b43_is_mode(dev->wl, IEEE80211_IF_TYPE_AP))
+	if (!b43_is_mode(wl, IEEE80211_IF_TYPE_AP))
 		return;
 
-	dev->irq_savedstate &= ~B43_IRQ_BEACON;
-	status = b43_read32(dev, B43_MMIO_STATUS2_BITFIELD);
+	/* This is the bottom half of the asynchronous beacon update. */
 
-	if (!dev->cached_beacon || ((status & 0x1) && (status & 0x2))) {
-		/* ACK beacon IRQ. */
-		b43_write32(dev, B43_MMIO_GEN_IRQ_REASON, B43_IRQ_BEACON);
-		dev->irq_savedstate |= B43_IRQ_BEACON;
-		if (dev->cached_beacon)
-			kfree_skb(dev->cached_beacon);
-		dev->cached_beacon = NULL;
-		return;
-	}
-	if (!(status & 0x1)) {
-		b43_write_beacon_template(dev, 0x68, 0x18, B43_CCK_RATE_1MB);
-		status |= 0x1;
-		b43_write32(dev, B43_MMIO_STATUS2_BITFIELD, status);
+	cmd = b43_read32(dev, B43_MMIO_MACCMD);
+	if (!(cmd & B43_MACCMD_BEACON0_VALID)) {
+		if (!wl->beacon0_uploaded) {
+			b43_write_beacon_template(dev, 0x68, 0x18,
+						  B43_CCK_RATE_1MB);
+			b43_write_probe_resp_template(dev, 0x268, 0x4A,
+						      &__b43_ratetable[3]);
+			wl->beacon0_uploaded = 1;
+		}
+		cmd |= B43_MACCMD_BEACON0_VALID;
 	}
-	if (!(status & 0x2)) {
-		b43_write_beacon_template(dev, 0x468, 0x1A, B43_CCK_RATE_1MB);
-		status |= 0x2;
-		b43_write32(dev, B43_MMIO_STATUS2_BITFIELD, status);
+	if (!(cmd & B43_MACCMD_BEACON1_VALID)) {
+		if (!wl->beacon1_uploaded) {
+			b43_write_beacon_template(dev, 0x468, 0x1A,
+						  B43_CCK_RATE_1MB);
+			wl->beacon1_uploaded = 1;
+		}
+		cmd |= B43_MACCMD_BEACON1_VALID;
 	}
+	b43_write32(dev, B43_MMIO_MACCMD, cmd);
 }
 
 static void handle_irq_ucode_debug(struct b43_wldev *dev)
@@ -1419,8 +1442,17 @@ static void b43_interrupt_tasklet(struct b43_wldev *dev)
 	if (unlikely(reason & B43_IRQ_MAC_TXERR))
 		b43err(dev->wl, "MAC transmission error\n");
 
-	if (unlikely(reason & B43_IRQ_PHY_TXERR))
+	if (unlikely(reason & B43_IRQ_PHY_TXERR)) {
 		b43err(dev->wl, "PHY transmission error\n");
+		rmb();
+		if (unlikely(atomic_dec_and_test(&dev->phy.txerr_cnt))) {
+			atomic_set(&dev->phy.txerr_cnt,
+				   B43_PHY_TX_BADNESS_LIMIT);
+			b43err(dev->wl, "Too many PHY TX errors, "
+					"restarting the controller\n");
+			b43_controller_restart(dev, "PHY TX errors");
+		}
+	}
 
 	if (unlikely(merged_dma_reason & (B43_DMAIRQ_FATALMASK |
 					  B43_DMAIRQ_NONFATALMASK))) {
@@ -1462,20 +1494,12 @@ static void b43_interrupt_tasklet(struct b43_wldev *dev)
 		handle_irq_noise(dev);
 
 	/* Check the DMA reason registers for received data. */
-	if (dma_reason[0] & B43_DMAIRQ_RX_DONE) {
-		if (b43_using_pio(dev))
-			b43_pio_rx(dev->pio.queue0);
-		else
-			b43_dma_rx(dev->dma.rx_ring0);
-	}
+	if (dma_reason[0] & B43_DMAIRQ_RX_DONE)
+		b43_dma_rx(dev->dma.rx_ring0);
+	if (dma_reason[3] & B43_DMAIRQ_RX_DONE)
+		b43_dma_rx(dev->dma.rx_ring3);
 	B43_WARN_ON(dma_reason[1] & B43_DMAIRQ_RX_DONE);
 	B43_WARN_ON(dma_reason[2] & B43_DMAIRQ_RX_DONE);
-	if (dma_reason[3] & B43_DMAIRQ_RX_DONE) {
-		if (b43_using_pio(dev))
-			b43_pio_rx(dev->pio.queue3);
-		else
-			b43_dma_rx(dev->dma.rx_ring3);
-	}
 	B43_WARN_ON(dma_reason[4] & B43_DMAIRQ_RX_DONE);
 	B43_WARN_ON(dma_reason[5] & B43_DMAIRQ_RX_DONE);
 
@@ -1487,29 +1511,8 @@ static void b43_interrupt_tasklet(struct b43_wldev *dev)
 	spin_unlock_irqrestore(&dev->wl->irq_lock, flags);
 }
 
-static void pio_irq_workaround(struct b43_wldev *dev, u16 base, int queueidx)
-{
-	u16 rxctl;
-
-	rxctl = b43_read16(dev, base + B43_PIO_RXCTL);
-	if (rxctl & B43_PIO_RXCTL_DATAAVAILABLE)
-		dev->dma_reason[queueidx] |= B43_DMAIRQ_RX_DONE;
-	else
-		dev->dma_reason[queueidx] &= ~B43_DMAIRQ_RX_DONE;
-}
-
 static void b43_interrupt_ack(struct b43_wldev *dev, u32 reason)
 {
-	if (b43_using_pio(dev) &&
-	    (dev->dev->id.revision < 3) &&
-	    (!(reason & B43_IRQ_PIO_WORKAROUND))) {
-		/* Apply a PIO specific workaround to the dma_reasons */
-		pio_irq_workaround(dev, B43_MMIO_PIO1_BASE, 0);
-		pio_irq_workaround(dev, B43_MMIO_PIO2_BASE, 1);
-		pio_irq_workaround(dev, B43_MMIO_PIO3_BASE, 2);
-		pio_irq_workaround(dev, B43_MMIO_PIO4_BASE, 3);
-	}
-
 	b43_write32(dev, B43_MMIO_GEN_IRQ_REASON, reason);
 
 	b43_write32(dev, B43_MMIO_DMA0_REASON, dev->dma_reason[0]);
@@ -1568,54 +1571,73 @@ static irqreturn_t b43_interrupt_handler(int irq, void *dev_id)
 	return ret;
 }
 
+static void do_release_fw(struct b43_firmware_file *fw)
+{
+	release_firmware(fw->data);
+	fw->data = NULL;
+	fw->filename = NULL;
+}
+
 static void b43_release_firmware(struct b43_wldev *dev)
 {
-	release_firmware(dev->fw.ucode);
-	dev->fw.ucode = NULL;
-	release_firmware(dev->fw.pcm);
-	dev->fw.pcm = NULL;
-	release_firmware(dev->fw.initvals);
-	dev->fw.initvals = NULL;
-	release_firmware(dev->fw.initvals_band);
-	dev->fw.initvals_band = NULL;
+	do_release_fw(&dev->fw.ucode);
+	do_release_fw(&dev->fw.pcm);
+	do_release_fw(&dev->fw.initvals);
+	do_release_fw(&dev->fw.initvals_band);
 }
 
-static void b43_print_fw_helptext(struct b43_wl *wl)
+static void b43_print_fw_helptext(struct b43_wl *wl, bool error)
 {
-	b43err(wl, "You must go to "
-	       "http://linuxwireless.org/en/users/Drivers/bcm43xx#devicefirmware "
-	       "and download the correct firmware (version 4).\n");
+	const char *text;
+
+	text = "You must go to "
+	       "http://linuxwireless.org/en/users/Drivers/b43#devicefirmware "
+	       "and download the latest firmware (version 4).\n";
+	if (error)
+		b43err(wl, text);
+	else
+		b43warn(wl, text);
 }
 
 static int do_request_fw(struct b43_wldev *dev,
 			 const char *name,
-			 const struct firmware **fw)
+			 struct b43_firmware_file *fw)
 {
 	char path[sizeof(modparam_fwpostfix) + 32];
+	const struct firmware *blob;
 	struct b43_fw_header *hdr;
 	u32 size;
 	int err;
 
-	if (!name)
+	if (!name) {
+		/* Don't fetch anything. Free possibly cached firmware. */
+		do_release_fw(fw);
 		return 0;
+	}
+	if (fw->filename) {
+		if (strcmp(fw->filename, name) == 0)
+			return 0; /* Already have this fw. */
+		/* Free the cached firmware first. */
+		do_release_fw(fw);
+	}
 
 	snprintf(path, ARRAY_SIZE(path),
 		 "b43%s/%s.fw",
 		 modparam_fwpostfix, name);
-	err = request_firmware(fw, path, dev->dev->dev);
+	err = request_firmware(&blob, path, dev->dev->dev);
 	if (err) {
 		b43err(dev->wl, "Firmware file \"%s\" not found "
 		       "or load failed.\n", path);
 		return err;
 	}
-	if ((*fw)->size < sizeof(struct b43_fw_header))
+	if (blob->size < sizeof(struct b43_fw_header))
 		goto err_format;
-	hdr = (struct b43_fw_header *)((*fw)->data);
+	hdr = (struct b43_fw_header *)(blob->data);
 	switch (hdr->type) {
 	case B43_FW_TYPE_UCODE:
 	case B43_FW_TYPE_PCM:
 		size = be32_to_cpu(hdr->size);
-		if (size != (*fw)->size - sizeof(struct b43_fw_header))
+		if (size != blob->size - sizeof(struct b43_fw_header))
 			goto err_format;
 		/* fallthrough */
 	case B43_FW_TYPE_IV:
@@ -1626,10 +1648,15 @@ static int do_request_fw(struct b43_wldev *dev,
 		goto err_format;
 	}
 
-	return err;
+	fw->data = blob;
+	fw->filename = name;
+
+	return 0;
 
 err_format:
 	b43err(dev->wl, "Firmware file \"%s\" format error.\n", path);
+	release_firmware(blob);
+
 	return -EPROTO;
 }
 
@@ -1641,90 +1668,101 @@ static int b43_request_firmware(struct b43_wldev *dev)
 	u32 tmshigh;
 	int err;
 
+	/* Get microcode */
 	tmshigh = ssb_read32(dev->dev, SSB_TMSHIGH);
-	if (!fw->ucode) {
+	if ((rev >= 5) && (rev <= 10))
+		filename = "ucode5";
+	else if ((rev >= 11) && (rev <= 12))
+		filename = "ucode11";
+	else if (rev >= 13)
+		filename = "ucode13";
+	else
+		goto err_no_ucode;
+	err = do_request_fw(dev, filename, &fw->ucode);
+	if (err)
+		goto err_load;
+
+	/* Get PCM code */
+	if ((rev >= 5) && (rev <= 10))
+		filename = "pcm5";
+	else if (rev >= 11)
+		filename = NULL;
+	else
+		goto err_no_pcm;
+	err = do_request_fw(dev, filename, &fw->pcm);
+	if (err)
+		goto err_load;
+
+	/* Get initvals */
+	switch (dev->phy.type) {
+	case B43_PHYTYPE_A:
+		if ((rev >= 5) && (rev <= 10)) {
+			if (tmshigh & B43_TMSHIGH_HAVE_2GHZ_PHY)
+				filename = "a0g1initvals5";
+			else
+				filename = "a0g0initvals5";
+		} else
+			goto err_no_initvals;
+		break;
+	case B43_PHYTYPE_G:
 		if ((rev >= 5) && (rev <= 10))
-			filename = "ucode5";
-		else if ((rev >= 11) && (rev <= 12))
-			filename = "ucode11";
+			filename = "b0g0initvals5";
 		else if (rev >= 13)
-			filename = "ucode13";
+			filename = "lp0initvals13";
 		else
-			goto err_no_ucode;
-		err = do_request_fw(dev, filename, &fw->ucode);
-		if (err)
-			goto err_load;
+			goto err_no_initvals;
+		break;
+	case B43_PHYTYPE_N:
+		if ((rev >= 11) && (rev <= 12))
+			filename = "n0initvals11";
+		else
+			goto err_no_initvals;
+		break;
+	default:
+		goto err_no_initvals;
 	}
-	if (!fw->pcm) {
+	err = do_request_fw(dev, filename, &fw->initvals);
+	if (err)
+		goto err_load;
+
+	/* Get bandswitch initvals */
+	switch (dev->phy.type) {
+	case B43_PHYTYPE_A:
+		if ((rev >= 5) && (rev <= 10)) {
+			if (tmshigh & B43_TMSHIGH_HAVE_2GHZ_PHY)
+				filename = "a0g1bsinitvals5";
+			else
+				filename = "a0g0bsinitvals5";
+		} else if (rev >= 11)
+			filename = NULL;
+		else
+			goto err_no_initvals;
+		break;
+	case B43_PHYTYPE_G:
 		if ((rev >= 5) && (rev <= 10))
-			filename = "pcm5";
+			filename = "b0g0bsinitvals5";
 		else if (rev >= 11)
 			filename = NULL;
 		else
-			goto err_no_pcm;
-		err = do_request_fw(dev, filename, &fw->pcm);
-		if (err)
-			goto err_load;
-	}
-	if (!fw->initvals) {
-		switch (dev->phy.type) {
-		case B43_PHYTYPE_A:
-			if ((rev >= 5) && (rev <= 10)) {
-				if (tmshigh & B43_TMSHIGH_GPHY)
-					filename = "a0g1initvals5";
-				else
-					filename = "a0g0initvals5";
-			} else
-				goto err_no_initvals;
-			break;
-		case B43_PHYTYPE_G:
-			if ((rev >= 5) && (rev <= 10))
-				filename = "b0g0initvals5";
-			else if (rev >= 13)
-				filename = "lp0initvals13";
-			else
-				goto err_no_initvals;
-			break;
-		default:
 			goto err_no_initvals;
-		}
-		err = do_request_fw(dev, filename, &fw->initvals);
-		if (err)
-			goto err_load;
-	}
-	if (!fw->initvals_band) {
-		switch (dev->phy.type) {
-		case B43_PHYTYPE_A:
-			if ((rev >= 5) && (rev <= 10)) {
-				if (tmshigh & B43_TMSHIGH_GPHY)
-					filename = "a0g1bsinitvals5";
-				else
-					filename = "a0g0bsinitvals5";
-			} else if (rev >= 11)
-				filename = NULL;
-			else
-				goto err_no_initvals;
-			break;
-		case B43_PHYTYPE_G:
-			if ((rev >= 5) && (rev <= 10))
-				filename = "b0g0bsinitvals5";
-			else if (rev >= 11)
-				filename = NULL;
-			else
-				goto err_no_initvals;
-			break;
-		default:
+		break;
+	case B43_PHYTYPE_N:
+		if ((rev >= 11) && (rev <= 12))
+			filename = "n0bsinitvals11";
+		else
 			goto err_no_initvals;
-		}
-		err = do_request_fw(dev, filename, &fw->initvals_band);
-		if (err)
-			goto err_load;
+		break;
+	default:
+		goto err_no_initvals;
 	}
+	err = do_request_fw(dev, filename, &fw->initvals_band);
+	if (err)
+		goto err_load;
 
 	return 0;
 
 err_load:
-	b43_print_fw_helptext(dev->wl);
+	b43_print_fw_helptext(dev->wl, 1);
 	goto error;
 
 err_no_ucode:
@@ -1754,22 +1792,33 @@ static int b43_upload_microcode(struct b43_wldev *dev)
 	const __be32 *data;
 	unsigned int i, len;
 	u16 fwrev, fwpatch, fwdate, fwtime;
-	u32 tmp;
+	u32 tmp, macctl;
 	int err = 0;
 
+	/* Jump the microcode PSM to offset 0 */
+	macctl = b43_read32(dev, B43_MMIO_MACCTL);
+	B43_WARN_ON(macctl & B43_MACCTL_PSM_RUN);
+	macctl |= B43_MACCTL_PSM_JMP0;
+	b43_write32(dev, B43_MMIO_MACCTL, macctl);
+	/* Zero out all microcode PSM registers and shared memory. */
+	for (i = 0; i < 64; i++)
+		b43_shm_write16(dev, B43_SHM_SCRATCH, i, 0);
+	for (i = 0; i < 4096; i += 2)
+		b43_shm_write16(dev, B43_SHM_SHARED, i, 0);
+
 	/* Upload Microcode. */
-	data = (__be32 *) (dev->fw.ucode->data + hdr_len);
-	len = (dev->fw.ucode->size - hdr_len) / sizeof(__be32);
+	data = (__be32 *) (dev->fw.ucode.data->data + hdr_len);
+	len = (dev->fw.ucode.data->size - hdr_len) / sizeof(__be32);
 	b43_shm_control_word(dev, B43_SHM_UCODE | B43_SHM_AUTOINC_W, 0x0000);
 	for (i = 0; i < len; i++) {
 		b43_write32(dev, B43_MMIO_SHM_DATA, be32_to_cpu(data[i]));
 		udelay(10);
 	}
 
-	if (dev->fw.pcm) {
+	if (dev->fw.pcm.data) {
 		/* Upload PCM data. */
-		data = (__be32 *) (dev->fw.pcm->data + hdr_len);
-		len = (dev->fw.pcm->size - hdr_len) / sizeof(__be32);
+		data = (__be32 *) (dev->fw.pcm.data->data + hdr_len);
+		len = (dev->fw.pcm.data->size - hdr_len) / sizeof(__be32);
 		b43_shm_control_word(dev, B43_SHM_HW, 0x01EA);
 		b43_write32(dev, B43_MMIO_SHM_DATA, 0x00004000);
 		/* No need for autoinc bit in SHM_HW */
@@ -1781,9 +1830,12 @@ static int b43_upload_microcode(struct b43_wldev *dev)
 	}
 
 	b43_write32(dev, B43_MMIO_GEN_IRQ_REASON, B43_IRQ_ALL);
-	b43_write32(dev, B43_MMIO_MACCTL,
-		    B43_MACCTL_PSM_RUN |
-		    B43_MACCTL_IHR_ENABLED | B43_MACCTL_INFRA);
+
+	/* Start the microcode PSM */
+	macctl = b43_read32(dev, B43_MMIO_MACCTL);
+	macctl &= ~B43_MACCTL_PSM_JMP0;
+	macctl |= B43_MACCTL_PSM_RUN;
+	b43_write32(dev, B43_MMIO_MACCTL, macctl);
 
 	/* Wait for the microcode to load and respond */
 	i = 0;
@@ -1792,13 +1844,17 @@ static int b43_upload_microcode(struct b43_wldev *dev)
 		if (tmp == B43_IRQ_MAC_SUSPENDED)
 			break;
 		i++;
-		if (i >= 50) {
+		if (i >= 20) {
 			b43err(dev->wl, "Microcode not responding\n");
-			b43_print_fw_helptext(dev->wl);
+			b43_print_fw_helptext(dev->wl, 1);
 			err = -ENODEV;
-			goto out;
+			goto error;
+		}
+		msleep_interruptible(50);
+		if (signal_pending(current)) {
+			err = -EINTR;
+			goto error;
 		}
-		udelay(10);
 	}
 	b43_read32(dev, B43_MMIO_GEN_IRQ_REASON);	/* dummy read */
 
@@ -1812,10 +1868,9 @@ static int b43_upload_microcode(struct b43_wldev *dev)
 		b43err(dev->wl, "YOUR FIRMWARE IS TOO OLD. Firmware from "
 		       "binary drivers older than version 4.x is unsupported. "
 		       "You must upgrade your firmware files.\n");
-		b43_print_fw_helptext(dev->wl);
-		b43_write32(dev, B43_MMIO_MACCTL, 0);
+		b43_print_fw_helptext(dev->wl, 1);
 		err = -EOPNOTSUPP;
-		goto out;
+		goto error;
 	}
 	b43dbg(dev->wl, "Loading firmware version %u.%u "
 	       "(20%.2i-%.2i-%.2i %.2i:%.2i:%.2i)\n",
@@ -1826,7 +1881,20 @@ static int b43_upload_microcode(struct b43_wldev *dev)
 	dev->fw.rev = fwrev;
 	dev->fw.patch = fwpatch;
 
-      out:
+	if (b43_is_old_txhdr_format(dev)) {
+		b43warn(dev->wl, "You are using an old firmware image. "
+			"Support for old firmware will be removed in July 2008.\n");
+		b43_print_fw_helptext(dev->wl, 0);
+	}
+
+	return 0;
+
+error:
+	macctl = b43_read32(dev, B43_MMIO_MACCTL);
+	macctl &= ~B43_MACCTL_PSM_RUN;
+	macctl |= B43_MACCTL_PSM_JMP0;
+	b43_write32(dev, B43_MMIO_MACCTL, macctl);
+
 	return err;
 }
 
@@ -1886,7 +1954,7 @@ static int b43_write_initvals(struct b43_wldev *dev,
 
 err_format:
 	b43err(dev->wl, "Initial Values Firmware file-format error.\n");
-	b43_print_fw_helptext(dev->wl);
+	b43_print_fw_helptext(dev->wl, 1);
 
 	return -EPROTO;
 }
@@ -1900,19 +1968,19 @@ static int b43_upload_initvals(struct b43_wldev *dev)
 	size_t count;
 	int err;
 
-	hdr = (const struct b43_fw_header *)(fw->initvals->data);
-	ivals = (const struct b43_iv *)(fw->initvals->data + hdr_len);
+	hdr = (const struct b43_fw_header *)(fw->initvals.data->data);
+	ivals = (const struct b43_iv *)(fw->initvals.data->data + hdr_len);
 	count = be32_to_cpu(hdr->size);
 	err = b43_write_initvals(dev, ivals, count,
-				 fw->initvals->size - hdr_len);
+				 fw->initvals.data->size - hdr_len);
 	if (err)
 		goto out;
-	if (fw->initvals_band) {
-		hdr = (const struct b43_fw_header *)(fw->initvals_band->data);
-		ivals = (const struct b43_iv *)(fw->initvals_band->data + hdr_len);
+	if (fw->initvals_band.data) {
+		hdr = (const struct b43_fw_header *)(fw->initvals_band.data->data);
+		ivals = (const struct b43_iv *)(fw->initvals_band.data->data + hdr_len);
 		count = be32_to_cpu(hdr->size);
 		err = b43_write_initvals(dev, ivals, count,
-					 fw->initvals_band->size - hdr_len);
+					 fw->initvals_band.data->size - hdr_len);
 		if (err)
 			goto out;
 	}
@@ -1949,7 +2017,7 @@ static int b43_gpio_init(struct b43_wldev *dev)
 		mask |= 0x0180;
 		set |= 0x0180;
 	}
-	if (dev->dev->bus->sprom.r1.boardflags_lo & B43_BFL_PACTRL) {
+	if (dev->dev->bus->sprom.boardflags_lo & B43_BFL_PACTRL) {
 		b43_write16(dev, B43_MMIO_GPIO_MASK,
 			    b43_read16(dev, B43_MMIO_GPIO_MASK)
 			    | 0x0200);
@@ -2119,6 +2187,7 @@ static void b43_rate_memory_init(struct b43_wldev *dev)
 	switch (dev->phy.type) {
 	case B43_PHYTYPE_A:
 	case B43_PHYTYPE_G:
+	case B43_PHYTYPE_N:
 		b43_rate_memory_write(dev, B43_OFDM_RATE_6MB, 1);
 		b43_rate_memory_write(dev, B43_OFDM_RATE_12MB, 1);
 		b43_rate_memory_write(dev, B43_OFDM_RATE_18MB, 1);
@@ -2148,13 +2217,19 @@ static void b43_mgmtframe_txantenna(struct b43_wldev *dev, int antenna)
 
 	switch (antenna) {
 	case B43_ANTENNA0:
-		ant |= B43_TX4_PHY_ANT0;
+		ant |= B43_TXH_PHY_ANT0;
 		break;
 	case B43_ANTENNA1:
-		ant |= B43_TX4_PHY_ANT1;
+		ant |= B43_TXH_PHY_ANT1;
+		break;
+	case B43_ANTENNA2:
+		ant |= B43_TXH_PHY_ANT2;
+		break;
+	case B43_ANTENNA3:
+		ant |= B43_TXH_PHY_ANT3;
 		break;
 	case B43_ANTENNA_AUTO:
-		ant |= B43_TX4_PHY_ANTLAST;
+		ant |= B43_TXH_PHY_ANT01AUTO;
 		break;
 	default:
 		B43_WARN_ON(1);
@@ -2164,15 +2239,15 @@ static void b43_mgmtframe_txantenna(struct b43_wldev *dev, int antenna)
 
 	/* For Beacons */
 	tmp = b43_shm_read16(dev, B43_SHM_SHARED, B43_SHM_SH_BEACPHYCTL);
-	tmp = (tmp & ~B43_TX4_PHY_ANT) | ant;
+	tmp = (tmp & ~B43_TXH_PHY_ANT) | ant;
 	b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_BEACPHYCTL, tmp);
 	/* For ACK/CTS */
 	tmp = b43_shm_read16(dev, B43_SHM_SHARED, B43_SHM_SH_ACKCTSPHYCTL);
-	tmp = (tmp & ~B43_TX4_PHY_ANT) | ant;
+	tmp = (tmp & ~B43_TXH_PHY_ANT) | ant;
 	b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_ACKCTSPHYCTL, tmp);
 	/* For Probe Resposes */
 	tmp = b43_shm_read16(dev, B43_SHM_SHARED, B43_SHM_SH_PRPHYCTL);
-	tmp = (tmp & ~B43_TX4_PHY_ANT) | ant;
+	tmp = (tmp & ~B43_TXH_PHY_ANT) | ant;
 	b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_PRPHYCTL, tmp);
 }
 
@@ -2180,7 +2255,6 @@ static void b43_mgmtframe_txantenna(struct b43_wldev *dev, int antenna)
 static void b43_chip_exit(struct b43_wldev *dev)
 {
 	b43_radio_turn_off(dev, 1);
-	b43_leds_exit(dev);
 	b43_gpio_cleanup(dev);
 	/* firmware is released later */
 }
@@ -2192,11 +2266,15 @@ static int b43_chip_init(struct b43_wldev *dev)
 {
 	struct b43_phy *phy = &dev->phy;
 	int err, tmp;
-	u32 value32;
+	u32 value32, macctl;
 	u16 value16;
 
-	b43_write32(dev, B43_MMIO_MACCTL,
-		    B43_MACCTL_PSM_JMP0 | B43_MACCTL_IHR_ENABLED);
+	/* Initialize the MAC control */
+	macctl = B43_MACCTL_IHR_ENABLED | B43_MACCTL_SHM_ENABLED;
+	if (dev->phy.gmode)
+		macctl |= B43_MACCTL_GMODE;
+	macctl |= B43_MACCTL_INFRA;
+	b43_write32(dev, B43_MMIO_MACCTL, macctl);
 
 	err = b43_request_firmware(dev);
 	if (err)
@@ -2208,11 +2286,10 @@ static int b43_chip_init(struct b43_wldev *dev)
 	err = b43_gpio_init(dev);
 	if (err)
 		goto out;	/* firmware is released later */
-	b43_leds_init(dev);
 
 	err = b43_upload_initvals(dev);
 	if (err)
-		goto err_leds_exit;
+		goto err_gpio_clean;
 	b43_radio_turn_on(dev);
 
 	b43_write16(dev, 0x03E6, 0x0000);
@@ -2242,14 +2319,6 @@ static int b43_chip_init(struct b43_wldev *dev)
 	b43_write32(dev, B43_MMIO_MACCTL, b43_read32(dev, B43_MMIO_MACCTL)
 		    | B43_MACCTL_INFRA);
 
-	if (b43_using_pio(dev)) {
-		b43_write32(dev, 0x0210, 0x00000100);
-		b43_write32(dev, 0x0230, 0x00000100);
-		b43_write32(dev, 0x0250, 0x00000100);
-		b43_write32(dev, 0x0270, 0x00000100);
-		b43_shm_write16(dev, B43_SHM_SHARED, 0x0034, 0x0000);
-	}
-
 	/* Probe Response Timeout value */
 	/* FIXME: Default to 0, has to be set by ioctl probably... :-/ */
 	b43_shm_write16(dev, B43_SHM_SHARED, 0x0074, 0x0000);
@@ -2288,8 +2357,7 @@ out:
 
 err_radio_off:
 	b43_radio_turn_off(dev, 1);
-err_leds_exit:
-	b43_leds_exit(dev);
+err_gpio_clean:
 	b43_gpio_cleanup(dev);
 	return err;
 }
@@ -2312,9 +2380,11 @@ static void b43_periodic_every60sec(struct b43_wldev *dev)
 {
 	struct b43_phy *phy = &dev->phy;
 
+	if (phy->type != B43_PHYTYPE_G)
+		return;
 	if (!b43_has_hardware_pctl(phy))
 		b43_lo_g_ctl_mark_all_unused(dev);
-	if (dev->dev->bus->sprom.r1.boardflags_lo & B43_BFL_RSSI) {
+	if (dev->dev->bus->sprom.boardflags_lo & B43_BFL_RSSI) {
 		b43_mac_suspend(dev);
 		b43_calc_nrssi_slope(dev);
 		if ((phy->radio_ver == 0x2050) && (phy->radio_rev == 8)) {
@@ -2366,6 +2436,9 @@ static void b43_periodic_every15sec(struct b43_wldev *dev)
 	}
 	b43_phy_xmitpower(dev);	//FIXME: unless scanning?
 	//TODO for APHY (temperature?)
+
+	atomic_set(&phy->txerr_cnt, B43_PHY_TX_BADNESS_LIMIT);
+	wmb();
 }
 
 static void do_periodic_work(struct b43_wldev *dev)
@@ -2423,32 +2496,42 @@ static void b43_periodic_tasks_setup(struct b43_wldev *dev)
 	queue_delayed_work(dev->wl->hw->workqueue, work, 0);
 }
 
-/* Validate access to the chip (SHM) */
+/* Check if communication with the device works correctly. */
 static int b43_validate_chipaccess(struct b43_wldev *dev)
 {
-	u32 value;
-	u32 shm_backup;
+	u32 v, backup;
 
-	shm_backup = b43_shm_read32(dev, B43_SHM_SHARED, 0);
-	b43_shm_write32(dev, B43_SHM_SHARED, 0, 0xAA5555AA);
-	if (b43_shm_read32(dev, B43_SHM_SHARED, 0) != 0xAA5555AA)
-		goto error;
+	backup = b43_shm_read32(dev, B43_SHM_SHARED, 0);
+
+	/* Check for read/write and endianness problems. */
 	b43_shm_write32(dev, B43_SHM_SHARED, 0, 0x55AAAA55);
 	if (b43_shm_read32(dev, B43_SHM_SHARED, 0) != 0x55AAAA55)
 		goto error;
-	b43_shm_write32(dev, B43_SHM_SHARED, 0, shm_backup);
-
-	value = b43_read32(dev, B43_MMIO_MACCTL);
-	if ((value | B43_MACCTL_GMODE) !=
-	    (B43_MACCTL_GMODE | B43_MACCTL_IHR_ENABLED))
+	b43_shm_write32(dev, B43_SHM_SHARED, 0, 0xAA5555AA);
+	if (b43_shm_read32(dev, B43_SHM_SHARED, 0) != 0xAA5555AA)
 		goto error;
 
-	value = b43_read32(dev, B43_MMIO_GEN_IRQ_REASON);
-	if (value)
+	b43_shm_write32(dev, B43_SHM_SHARED, 0, backup);
+
+	if ((dev->dev->id.revision >= 3) && (dev->dev->id.revision <= 10)) {
+		/* The 32bit register shadows the two 16bit registers
+		 * with update sideeffects. Validate this. */
+		b43_write16(dev, B43_MMIO_TSF_CFP_START, 0xAAAA);
+		b43_write32(dev, B43_MMIO_TSF_CFP_START, 0xCCCCBBBB);
+		if (b43_read16(dev, B43_MMIO_TSF_CFP_START_LOW) != 0xBBBB)
+			goto error;
+		if (b43_read16(dev, B43_MMIO_TSF_CFP_START_HIGH) != 0xCCCC)
+			goto error;
+	}
+	b43_write32(dev, B43_MMIO_TSF_CFP_START, 0);
+
+	v = b43_read32(dev, B43_MMIO_MACCTL);
+	v |= B43_MACCTL_GMODE;
+	if (v != (B43_MACCTL_GMODE | B43_MACCTL_IHR_ENABLED))
 		goto error;
 
 	return 0;
-      error:
+error:
 	b43err(dev->wl, "Failed to validate the chipaccess\n");
 	return -ENODEV;
 }
@@ -2511,40 +2594,35 @@ static int b43_rng_init(struct b43_wl *wl)
 	return err;
 }
 
-static int b43_tx(struct ieee80211_hw *hw,
-		  struct sk_buff *skb, struct ieee80211_tx_control *ctl)
+static int b43_op_tx(struct ieee80211_hw *hw,
+		     struct sk_buff *skb,
+		     struct ieee80211_tx_control *ctl)
 {
 	struct b43_wl *wl = hw_to_b43_wl(hw);
 	struct b43_wldev *dev = wl->current_dev;
 	int err = -ENODEV;
-	unsigned long flags;
 
 	if (unlikely(!dev))
 		goto out;
 	if (unlikely(b43_status(dev) < B43_STAT_STARTED))
 		goto out;
 	/* DMA-TX is done without a global lock. */
-	if (b43_using_pio(dev)) {
-		spin_lock_irqsave(&wl->irq_lock, flags);
-		err = b43_pio_tx(dev, skb, ctl);
-		spin_unlock_irqrestore(&wl->irq_lock, flags);
-	} else
-		err = b43_dma_tx(dev, skb, ctl);
-      out:
+	err = b43_dma_tx(dev, skb, ctl);
+out:
 	if (unlikely(err))
 		return NETDEV_TX_BUSY;
 	return NETDEV_TX_OK;
 }
 
-static int b43_conf_tx(struct ieee80211_hw *hw,
-		       int queue,
-		       const struct ieee80211_tx_queue_params *params)
+static int b43_op_conf_tx(struct ieee80211_hw *hw,
+			  int queue,
+			  const struct ieee80211_tx_queue_params *params)
 {
 	return 0;
 }
 
-static int b43_get_tx_stats(struct ieee80211_hw *hw,
-			    struct ieee80211_tx_queue_stats *stats)
+static int b43_op_get_tx_stats(struct ieee80211_hw *hw,
+			       struct ieee80211_tx_queue_stats *stats)
 {
 	struct b43_wl *wl = hw_to_b43_wl(hw);
 	struct b43_wldev *dev = wl->current_dev;
@@ -2555,19 +2633,16 @@ static int b43_get_tx_stats(struct ieee80211_hw *hw,
 		goto out;
 	spin_lock_irqsave(&wl->irq_lock, flags);
 	if (likely(b43_status(dev) >= B43_STAT_STARTED)) {
-		if (b43_using_pio(dev))
-			b43_pio_get_tx_stats(dev, stats);
-		else
-			b43_dma_get_tx_stats(dev, stats);
+		b43_dma_get_tx_stats(dev, stats);
 		err = 0;
 	}
 	spin_unlock_irqrestore(&wl->irq_lock, flags);
-      out:
+out:
 	return err;
 }
 
-static int b43_get_stats(struct ieee80211_hw *hw,
-			 struct ieee80211_low_level_stats *stats)
+static int b43_op_get_stats(struct ieee80211_hw *hw,
+			    struct ieee80211_low_level_stats *stats)
 {
 	struct b43_wl *wl = hw_to_b43_wl(hw);
 	unsigned long flags;
@@ -2706,8 +2781,36 @@ static int b43_switch_phymode(struct b43_wl *wl, unsigned int new_mode)
 	return err;
 }
 
-static int b43_antenna_from_ieee80211(u8 antenna)
+/* Check if the use of the antenna that ieee80211 told us to
+ * use is possible. This will fall back to DEFAULT.
+ * "antenna_nr" is the antenna identifier we got from ieee80211. */
+u8 b43_ieee80211_antenna_sanitize(struct b43_wldev *dev,
+				  u8 antenna_nr)
 {
+	u8 antenna_mask;
+
+	if (antenna_nr == 0) {
+		/* Zero means "use default antenna". That's always OK. */
+		return 0;
+	}
+
+	/* Get the mask of available antennas. */
+	if (dev->phy.gmode)
+		antenna_mask = dev->dev->bus->sprom.ant_available_bg;
+	else
+		antenna_mask = dev->dev->bus->sprom.ant_available_a;
+
+	if (!(antenna_mask & (1 << (antenna_nr - 1)))) {
+		/* This antenna is not available. Fall back to default. */
+		return 0;
+	}
+
+	return antenna_nr;
+}
+
+static int b43_antenna_from_ieee80211(struct b43_wldev *dev, u8 antenna)
+{
+	antenna = b43_ieee80211_antenna_sanitize(dev, antenna);
 	switch (antenna) {
 	case 0:		/* default/diversity */
 		return B43_ANTENNA_DEFAULT;
@@ -2715,37 +2818,34 @@ static int b43_antenna_from_ieee80211(u8 antenna)
 		return B43_ANTENNA0;
 	case 2:		/* Antenna 1 */
 		return B43_ANTENNA1;
+	case 3:		/* Antenna 2 */
+		return B43_ANTENNA2;
+	case 4:		/* Antenna 3 */
+		return B43_ANTENNA3;
 	default:
 		return B43_ANTENNA_DEFAULT;
 	}
 }
 
-static int b43_dev_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf)
+static int b43_op_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf)
 {
 	struct b43_wl *wl = hw_to_b43_wl(hw);
 	struct b43_wldev *dev;
 	struct b43_phy *phy;
 	unsigned long flags;
 	unsigned int new_phymode = 0xFFFF;
-	int antenna_tx;
-	int antenna_rx;
+	int antenna;
 	int err = 0;
 	u32 savedirqs;
 
-	antenna_tx = b43_antenna_from_ieee80211(conf->antenna_sel_tx);
-	antenna_rx = b43_antenna_from_ieee80211(conf->antenna_sel_rx);
-
 	mutex_lock(&wl->mutex);
 
 	/* Switch the PHY mode (if necessary). */
-	switch (conf->phymode) {
-	case MODE_IEEE80211A:
+	switch (conf->channel->band) {
+	case IEEE80211_BAND_5GHZ:
 		new_phymode = B43_PHYMODE_A;
 		break;
-	case MODE_IEEE80211B:
-		new_phymode = B43_PHYMODE_B;
-		break;
-	case MODE_IEEE80211G:
+	case IEEE80211_BAND_2GHZ:
 		new_phymode = B43_PHYMODE_G;
 		break;
 	default:
@@ -2771,8 +2871,8 @@ static int b43_dev_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf)
 
 	/* Switch to the requested channel.
 	 * The firmware takes care of races with the TX handler. */
-	if (conf->channel_val != phy->channel)
-		b43_radio_selectchannel(dev, conf->channel_val, 0);
+	if (conf->channel->hw_value != phy->channel)
+		b43_radio_selectchannel(dev, conf->channel->hw_value, 0);
 
 	/* Enable/Disable ShortSlot timing. */
 	if ((!!(conf->flags & IEEE80211_CONF_SHORT_SLOT_TIME)) !=
@@ -2784,6 +2884,8 @@ static int b43_dev_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf)
 			b43_short_slot_timing_disable(dev);
 	}
 
+	dev->wl->radiotap_enabled = !!(conf->flags & IEEE80211_CONF_RADIOTAP);
+
 	/* Adjust the desired TX power level. */
 	if (conf->power_level != 0) {
 		if (conf->power_level != phy->power_level) {
@@ -2793,8 +2895,10 @@ static int b43_dev_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf)
 	}
 
 	/* Antennas for RX and management frame TX. */
-	b43_mgmtframe_txantenna(dev, antenna_tx);
-	b43_set_rx_antenna(dev, antenna_rx);
+	antenna = b43_antenna_from_ieee80211(dev, conf->antenna_sel_tx);
+	b43_mgmtframe_txantenna(dev, antenna);
+	antenna = b43_antenna_from_ieee80211(dev, conf->antenna_sel_rx);
+	b43_set_rx_antenna(dev, antenna);
 
 	/* Update templates for AP mode. */
 	if (b43_is_mode(wl, IEEE80211_IF_TYPE_AP))
@@ -2825,22 +2929,30 @@ static int b43_dev_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf)
 	return err;
 }
 
-static int b43_dev_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
+static int b43_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
 			   const u8 *local_addr, const u8 *addr,
 			   struct ieee80211_key_conf *key)
 {
 	struct b43_wl *wl = hw_to_b43_wl(hw);
-	struct b43_wldev *dev = wl->current_dev;
+	struct b43_wldev *dev;
 	unsigned long flags;
 	u8 algorithm;
 	u8 index;
-	int err = -EINVAL;
+	int err;
+	DECLARE_MAC_BUF(mac);
 
 	if (modparam_nohwcrypt)
 		return -ENOSPC; /* User disabled HW-crypto */
 
-	if (!dev)
-		return -ENODEV;
+	mutex_lock(&wl->mutex);
+	spin_lock_irqsave(&wl->irq_lock, flags);
+
+	dev = wl->current_dev;
+	err = -ENODEV;
+	if (!dev || b43_status(dev) < B43_STAT_INITIALIZED)
+		goto out_unlock;
+
+	err = -EINVAL;
 	switch (key->alg) {
 	case ALG_WEP:
 		if (key->keylen == 5)
@@ -2856,20 +2968,11 @@ static int b43_dev_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
 		break;
 	default:
 		B43_WARN_ON(1);
-		goto out;
+		goto out_unlock;
 	}
-
 	index = (u8) (key->keyidx);
 	if (index > 3)
-		goto out;
-
-	mutex_lock(&wl->mutex);
-	spin_lock_irqsave(&wl->irq_lock, flags);
-
-	if (b43_status(dev) < B43_STAT_INITIALIZED) {
-		err = -ENODEV;
 		goto out_unlock;
-	}
 
 	switch (cmd) {
 	case SET_KEY:
@@ -2915,19 +3018,18 @@ static int b43_dev_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
 out_unlock:
 	spin_unlock_irqrestore(&wl->irq_lock, flags);
 	mutex_unlock(&wl->mutex);
-out:
 	if (!err) {
 		b43dbg(wl, "%s hardware based encryption for keyidx: %d, "
-		       "mac: " MAC_FMT "\n",
+		       "mac: %s\n",
 		       cmd == SET_KEY ? "Using" : "Disabling", key->keyidx,
-		       MAC_ARG(addr));
+		       print_mac(mac, addr));
 	}
 	return err;
 }
 
-static void b43_configure_filter(struct ieee80211_hw *hw,
-				 unsigned int changed, unsigned int *fflags,
-				 int mc_count, struct dev_addr_list *mc_list)
+static void b43_op_configure_filter(struct ieee80211_hw *hw,
+				    unsigned int changed, unsigned int *fflags,
+				    int mc_count, struct dev_addr_list *mc_list)
 {
 	struct b43_wl *wl = hw_to_b43_wl(hw);
 	struct b43_wldev *dev = wl->current_dev;
@@ -2962,8 +3064,9 @@ static void b43_configure_filter(struct ieee80211_hw *hw,
 	spin_unlock_irqrestore(&wl->irq_lock, flags);
 }
 
-static int b43_config_interface(struct ieee80211_hw *hw,
-				int if_id, struct ieee80211_if_conf *conf)
+static int b43_op_config_interface(struct ieee80211_hw *hw,
+				   struct ieee80211_vif *vif,
+				   struct ieee80211_if_conf *conf)
 {
 	struct b43_wl *wl = hw_to_b43_wl(hw);
 	struct b43_wldev *dev = wl->current_dev;
@@ -2973,7 +3076,7 @@ static int b43_config_interface(struct ieee80211_hw *hw,
 		return -ENODEV;
 	mutex_lock(&wl->mutex);
 	spin_lock_irqsave(&wl->irq_lock, flags);
-	B43_WARN_ON(wl->if_id != if_id);
+	B43_WARN_ON(wl->vif != vif);
 	if (conf->bssid)
 		memcpy(wl->bssid, conf->bssid, ETH_ALEN);
 	else
@@ -2983,7 +3086,7 @@ static int b43_config_interface(struct ieee80211_hw *hw,
 			B43_WARN_ON(conf->type != IEEE80211_IF_TYPE_AP);
 			b43_set_ssid(dev, conf->ssid, conf->ssid_len);
 			if (conf->beacon)
-				b43_refresh_templates(dev, conf->beacon);
+				b43_update_templates(wl, conf->beacon);
 		}
 		b43_write_mac_bssid_templates(dev);
 	}
@@ -3001,6 +3104,16 @@ static void b43_wireless_core_stop(struct b43_wldev *dev)
 
 	if (b43_status(dev) < B43_STAT_STARTED)
 		return;
+
+	/* Disable and sync interrupts. We must do this before than
+	 * setting the status to INITIALIZED, as the interrupt handler
+	 * won't care about IRQs then. */
+	spin_lock_irqsave(&wl->irq_lock, flags);
+	dev->irq_savedstate = b43_interrupt_disable(dev, B43_IRQ_ALL);
+	b43_read32(dev, B43_MMIO_GEN_IRQ_MASK);	/* flush */
+	spin_unlock_irqrestore(&wl->irq_lock, flags);
+	b43_synchronize_irq(dev);
+
 	b43_set_status(dev, B43_STAT_INITIALIZED);
 
 	mutex_unlock(&wl->mutex);
@@ -3011,13 +3124,6 @@ static void b43_wireless_core_stop(struct b43_wldev *dev)
 
 	ieee80211_stop_queues(wl->hw);	//FIXME this could cause a deadlock, as mac80211 seems buggy.
 
-	/* Disable and sync interrupts. */
-	spin_lock_irqsave(&wl->irq_lock, flags);
-	dev->irq_savedstate = b43_interrupt_disable(dev, B43_IRQ_ALL);
-	b43_read32(dev, B43_MMIO_GEN_IRQ_MASK);	/* flush */
-	spin_unlock_irqrestore(&wl->irq_lock, flags);
-	b43_synchronize_irq(dev);
-
 	b43_mac_suspend(dev);
 	free_irq(dev->dev->irq, dev);
 	b43dbg(wl, "Wireless interface stopped\n");
@@ -3083,9 +3189,15 @@ static int b43_phy_versioning(struct b43_wldev *dev)
 			unsupported = 1;
 		break;
 	case B43_PHYTYPE_G:
-		if (phy_rev > 8)
+		if (phy_rev > 9)
+			unsupported = 1;
+		break;
+#ifdef CONFIG_B43_NPHY
+	case B43_PHYTYPE_N:
+		if (phy_rev > 1)
 			unsupported = 1;
 		break;
+#endif
 	default:
 		unsupported = 1;
 	};
@@ -3108,14 +3220,15 @@ static int b43_phy_versioning(struct b43_wldev *dev)
 			tmp = 0x5205017F;
 	} else {
 		b43_write16(dev, B43_MMIO_RADIO_CONTROL, B43_RADIOCTL_ID);
-		tmp = b43_read16(dev, B43_MMIO_RADIO_DATA_HIGH);
-		tmp <<= 16;
+		tmp = b43_read16(dev, B43_MMIO_RADIO_DATA_LOW);
 		b43_write16(dev, B43_MMIO_RADIO_CONTROL, B43_RADIOCTL_ID);
-		tmp |= b43_read16(dev, B43_MMIO_RADIO_DATA_LOW);
+		tmp |= (u32)b43_read16(dev, B43_MMIO_RADIO_DATA_HIGH) << 16;
 	}
 	radio_manuf = (tmp & 0x00000FFF);
 	radio_ver = (tmp & 0x0FFFF000) >> 12;
 	radio_rev = (tmp & 0xF0000000) >> 28;
+	if (radio_manuf != 0x17F /* Broadcom */)
+		unsupported = 1;
 	switch (phy_type) {
 	case B43_PHYTYPE_A:
 		if (radio_ver != 0x2060)
@@ -3133,6 +3246,10 @@ static int b43_phy_versioning(struct b43_wldev *dev)
 		if (radio_ver != 0x2050)
 			unsupported = 1;
 		break;
+	case B43_PHYTYPE_N:
+		if (radio_ver != 0x2055)
+			unsupported = 1;
+		break;
 	default:
 		B43_WARN_ON(1);
 	}
@@ -3165,9 +3282,6 @@ static void setup_struct_phy_for_init(struct b43_wldev *dev,
 	memset(phy->minlowsig, 0xFF, sizeof(phy->minlowsig));
 	memset(phy->minlowsigpos, 0, sizeof(phy->minlowsigpos));
 
-	/* Flags */
-	phy->locked = 0;
-
 	phy->aci_enable = 0;
 	phy->aci_wlan_automatic = 0;
 	phy->aci_hw_rssi = 0;
@@ -3194,17 +3308,22 @@ static void setup_struct_phy_for_init(struct b43_wldev *dev,
 	phy->lofcal = 0xFFFF;
 	phy->initval = 0xFFFF;
 
-	spin_lock_init(&phy->lock);
 	phy->interfmode = B43_INTERFMODE_NONE;
 	phy->channel = 0xFF;
 
 	phy->hardware_power_control = !!modparam_hwpctl;
+
+	/* PHY TX errors counter. */
+	atomic_set(&phy->txerr_cnt, B43_PHY_TX_BADNESS_LIMIT);
+
+	/* OFDM-table address caching. */
+	phy->ofdmtab_addr_direction = B43_OFDMTAB_DIRECTION_UNKNOWN;
 }
 
 static void setup_struct_wldev_for_init(struct b43_wldev *dev)
 {
-	/* Flags */
-	dev->reg124_set_0x4 = 0;
+	dev->dfq_valid = 0;
+
 	/* Assume the radio is enabled. If it's not enabled, the state will
 	 * immediately get fixed on the first periodic work run. */
 	dev->radio_hw_enable = 1;
@@ -3230,13 +3349,13 @@ static void b43_bluetooth_coext_enable(struct b43_wldev *dev)
 	struct ssb_sprom *sprom = &dev->dev->bus->sprom;
 	u32 hf;
 
-	if (!(sprom->r1.boardflags_lo & B43_BFL_BTCOEXIST))
+	if (!(sprom->boardflags_lo & B43_BFL_BTCOEXIST))
 		return;
 	if (dev->phy.type != B43_PHYTYPE_B && !dev->phy.gmode)
 		return;
 
 	hf = b43_hf_read(dev);
-	if (sprom->r1.boardflags_lo & B43_BFL_BTCMOD)
+	if (sprom->boardflags_lo & B43_BFL_BTCMOD)
 		hf |= B43_HF_BTCOEXALT;
 	else
 		hf |= B43_HF_BTCOEX;
@@ -3275,23 +3394,42 @@ static void b43_imcfglo_timeouts_workaround(struct b43_wldev *dev)
 #endif /* CONFIG_SSB_DRIVER_PCICORE */
 }
 
+/* Write the short and long frame retry limit values. */
+static void b43_set_retry_limits(struct b43_wldev *dev,
+				 unsigned int short_retry,
+				 unsigned int long_retry)
+{
+	/* The retry limit is a 4-bit counter. Enforce this to avoid overflowing
+	 * the chip-internal counter. */
+	short_retry = min(short_retry, (unsigned int)0xF);
+	long_retry = min(long_retry, (unsigned int)0xF);
+
+	b43_shm_write16(dev, B43_SHM_SCRATCH, B43_SHM_SC_SRLIMIT,
+			short_retry);
+	b43_shm_write16(dev, B43_SHM_SCRATCH, B43_SHM_SC_LRLIMIT,
+			long_retry);
+}
+
 /* Shutdown a wireless core */
 /* Locking: wl->mutex */
 static void b43_wireless_core_exit(struct b43_wldev *dev)
 {
 	struct b43_phy *phy = &dev->phy;
+	u32 macctl;
 
 	B43_WARN_ON(b43_status(dev) > B43_STAT_INITIALIZED);
 	if (b43_status(dev) != B43_STAT_INITIALIZED)
 		return;
 	b43_set_status(dev, B43_STAT_UNINIT);
 
-	mutex_unlock(&dev->wl->mutex);
-	b43_rfkill_exit(dev);
-	mutex_lock(&dev->wl->mutex);
+	/* Stop the microcode PSM. */
+	macctl = b43_read32(dev, B43_MMIO_MACCTL);
+	macctl &= ~B43_MACCTL_PSM_RUN;
+	macctl |= B43_MACCTL_PSM_JMP0;
+	b43_write32(dev, B43_MMIO_MACCTL, macctl);
 
+	b43_leds_exit(dev);
 	b43_rng_exit(dev->wl);
-	b43_pio_free(dev);
 	b43_dma_free(dev);
 	b43_chip_exit(dev);
 	b43_radio_turn_off(dev, 1);
@@ -3300,6 +3438,11 @@ static void b43_wireless_core_exit(struct b43_wldev *dev)
 		kfree(phy->tssi2dbm);
 	kfree(phy->lo_control);
 	phy->lo_control = NULL;
+	if (dev->wl->current_beacon) {
+		dev_kfree_skb_any(dev->wl->current_beacon);
+		dev->wl->current_beacon = NULL;
+	}
+
 	ssb_device_disable(dev->dev, 0);
 	ssb_bus_may_powerdown(dev->dev->bus);
 }
@@ -3354,7 +3497,7 @@ static int b43_wireless_core_init(struct b43_wldev *dev)
 		hf |= B43_HF_SYMW;
 		if (phy->rev == 1)
 			hf |= B43_HF_GDCW;
-		if (sprom->r1.boardflags_lo & B43_BFL_PACTRL)
+		if (sprom->boardflags_lo & B43_BFL_PACTRL)
 			hf |= B43_HF_OFDMPABOOST;
 	} else if (phy->type == B43_PHYTYPE_B) {
 		hf |= B43_HF_SYMW;
@@ -3363,15 +3506,8 @@ static int b43_wireless_core_init(struct b43_wldev *dev)
 	}
 	b43_hf_write(dev, hf);
 
-	/* Short/Long Retry Limit.
-	 * The retry-limit is a 4-bit counter. Enforce this to avoid overflowing
-	 * the chip-internal counter.
-	 */
-	tmp = limit_value(modparam_short_retry, 0, 0xF);
-	b43_shm_write16(dev, B43_SHM_SCRATCH, B43_SHM_SC_SRLIMIT, tmp);
-	tmp = limit_value(modparam_long_retry, 0, 0xF);
-	b43_shm_write16(dev, B43_SHM_SCRATCH, B43_SHM_SC_LRLIMIT, tmp);
-
+	b43_set_retry_limits(dev, B43_DEFAULT_SHORT_RETRY_LIMIT,
+			     B43_DEFAULT_LONG_RETRY_LIMIT);
 	b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_SFFBLIM, 3);
 	b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_LFFBLIM, 2);
 
@@ -3392,17 +3528,10 @@ static int b43_wireless_core_init(struct b43_wldev *dev)
 	/* Maximum Contention Window */
 	b43_shm_write16(dev, B43_SHM_SCRATCH, B43_SHM_SC_MAXCONT, 0x3FF);
 
-	do {
-		if (b43_using_pio(dev)) {
-			err = b43_pio_init(dev);
-		} else {
-			err = b43_dma_init(dev);
-			if (!err)
-				b43_qos_init(dev);
-		}
-	} while (err == -EAGAIN);
+	err = b43_dma_init(dev);
 	if (err)
 		goto err_chip_exit;
+	b43_qos_init(dev);
 
 //FIXME
 #if 1
@@ -3414,16 +3543,14 @@ static int b43_wireless_core_init(struct b43_wldev *dev)
 	b43_bluetooth_coext_enable(dev);
 
 	ssb_bus_powerup(bus, 1);	/* Enable dynamic PCTL */
-	memset(wl->bssid, 0, ETH_ALEN);
-	memset(wl->mac_addr, 0, ETH_ALEN);
 	b43_upload_card_macaddress(dev);
 	b43_security_init(dev);
-	b43_rfkill_init(dev);
 	b43_rng_init(wl);
 
 	b43_set_status(dev, B43_STAT_INITIALIZED);
 
-      out:
+	b43_leds_init(dev);
+out:
 	return err;
 
       err_chip_exit:
@@ -3440,8 +3567,8 @@ static int b43_wireless_core_init(struct b43_wldev *dev)
 	return err;
 }
 
-static int b43_add_interface(struct ieee80211_hw *hw,
-			     struct ieee80211_if_init_conf *conf)
+static int b43_op_add_interface(struct ieee80211_hw *hw,
+				struct ieee80211_if_init_conf *conf)
 {
 	struct b43_wl *wl = hw_to_b43_wl(hw);
 	struct b43_wldev *dev;
@@ -3464,7 +3591,7 @@ static int b43_add_interface(struct ieee80211_hw *hw,
 
 	dev = wl->current_dev;
 	wl->operating = 1;
-	wl->if_id = conf->if_id;
+	wl->vif = conf->vif;
 	wl->if_type = conf->type;
 	memcpy(wl->mac_addr, conf->mac_addr, ETH_ALEN);
 
@@ -3480,8 +3607,8 @@ static int b43_add_interface(struct ieee80211_hw *hw,
 	return err;
 }
 
-static void b43_remove_interface(struct ieee80211_hw *hw,
-				 struct ieee80211_if_init_conf *conf)
+static void b43_op_remove_interface(struct ieee80211_hw *hw,
+				    struct ieee80211_if_init_conf *conf)
 {
 	struct b43_wl *wl = hw_to_b43_wl(hw);
 	struct b43_wldev *dev = wl->current_dev;
@@ -3492,7 +3619,8 @@ static void b43_remove_interface(struct ieee80211_hw *hw,
 	mutex_lock(&wl->mutex);
 
 	B43_WARN_ON(!wl->operating);
-	B43_WARN_ON(wl->if_id != conf->if_id);
+	B43_WARN_ON(wl->vif != conf->vif);
+	wl->vif = NULL;
 
 	wl->operating = 0;
 
@@ -3505,19 +3633,34 @@ static void b43_remove_interface(struct ieee80211_hw *hw,
 	mutex_unlock(&wl->mutex);
 }
 
-static int b43_start(struct ieee80211_hw *hw)
+static int b43_op_start(struct ieee80211_hw *hw)
 {
 	struct b43_wl *wl = hw_to_b43_wl(hw);
 	struct b43_wldev *dev = wl->current_dev;
 	int did_init = 0;
 	int err = 0;
+	bool do_rfkill_exit = 0;
+
+	/* Kill all old instance specific information to make sure
+	 * the card won't use it in the short timeframe between start
+	 * and mac80211 reconfiguring it. */
+	memset(wl->bssid, 0, ETH_ALEN);
+	memset(wl->mac_addr, 0, ETH_ALEN);
+	wl->filter_flags = 0;
+	wl->radiotap_enabled = 0;
+
+	/* First register RFkill.
+	 * LEDs that are registered later depend on it. */
+	b43_rfkill_init(dev);
 
 	mutex_lock(&wl->mutex);
 
 	if (b43_status(dev) < B43_STAT_INITIALIZED) {
 		err = b43_wireless_core_init(dev);
-		if (err)
+		if (err) {
+			do_rfkill_exit = 1;
 			goto out_mutex_unlock;
+		}
 		did_init = 1;
 	}
 
@@ -3526,6 +3669,7 @@ static int b43_start(struct ieee80211_hw *hw)
 		if (err) {
 			if (did_init)
 				b43_wireless_core_exit(dev);
+			do_rfkill_exit = 1;
 			goto out_mutex_unlock;
 		}
 	}
@@ -3533,14 +3677,19 @@ static int b43_start(struct ieee80211_hw *hw)
  out_mutex_unlock:
 	mutex_unlock(&wl->mutex);
 
+	if (do_rfkill_exit)
+		b43_rfkill_exit(dev);
+
 	return err;
 }
 
-static void b43_stop(struct ieee80211_hw *hw)
+static void b43_op_stop(struct ieee80211_hw *hw)
 {
 	struct b43_wl *wl = hw_to_b43_wl(hw);
 	struct b43_wldev *dev = wl->current_dev;
 
+	b43_rfkill_exit(dev);
+
 	mutex_lock(&wl->mutex);
 	if (b43_status(dev) >= B43_STAT_STARTED)
 		b43_wireless_core_stop(dev);
@@ -3548,19 +3697,76 @@ static void b43_stop(struct ieee80211_hw *hw)
 	mutex_unlock(&wl->mutex);
 }
 
+static int b43_op_set_retry_limit(struct ieee80211_hw *hw,
+				  u32 short_retry_limit, u32 long_retry_limit)
+{
+	struct b43_wl *wl = hw_to_b43_wl(hw);
+	struct b43_wldev *dev;
+	int err = 0;
+
+	mutex_lock(&wl->mutex);
+	dev = wl->current_dev;
+	if (unlikely(!dev || (b43_status(dev) < B43_STAT_INITIALIZED))) {
+		err = -ENODEV;
+		goto out_unlock;
+	}
+	b43_set_retry_limits(dev, short_retry_limit, long_retry_limit);
+out_unlock:
+	mutex_unlock(&wl->mutex);
+
+	return err;
+}
+
+static int b43_op_beacon_set_tim(struct ieee80211_hw *hw, int aid, int set)
+{
+	struct b43_wl *wl = hw_to_b43_wl(hw);
+	struct sk_buff *beacon;
+	unsigned long flags;
+
+	/* We could modify the existing beacon and set the aid bit in
+	 * the TIM field, but that would probably require resizing and
+	 * moving of data within the beacon template.
+	 * Simply request a new beacon and let mac80211 do the hard work. */
+	beacon = ieee80211_beacon_get(hw, wl->vif, NULL);
+	if (unlikely(!beacon))
+		return -ENOMEM;
+	spin_lock_irqsave(&wl->irq_lock, flags);
+	b43_update_templates(wl, beacon);
+	spin_unlock_irqrestore(&wl->irq_lock, flags);
+
+	return 0;
+}
+
+static int b43_op_ibss_beacon_update(struct ieee80211_hw *hw,
+				     struct sk_buff *beacon,
+				     struct ieee80211_tx_control *ctl)
+{
+	struct b43_wl *wl = hw_to_b43_wl(hw);
+	unsigned long flags;
+
+	spin_lock_irqsave(&wl->irq_lock, flags);
+	b43_update_templates(wl, beacon);
+	spin_unlock_irqrestore(&wl->irq_lock, flags);
+
+	return 0;
+}
+
 static const struct ieee80211_ops b43_hw_ops = {
-	.tx = b43_tx,
-	.conf_tx = b43_conf_tx,
-	.add_interface = b43_add_interface,
-	.remove_interface = b43_remove_interface,
-	.config = b43_dev_config,
-	.config_interface = b43_config_interface,
-	.configure_filter = b43_configure_filter,
-	.set_key = b43_dev_set_key,
-	.get_stats = b43_get_stats,
-	.get_tx_stats = b43_get_tx_stats,
-	.start = b43_start,
-	.stop = b43_stop,
+	.tx			= b43_op_tx,
+	.conf_tx		= b43_op_conf_tx,
+	.add_interface		= b43_op_add_interface,
+	.remove_interface	= b43_op_remove_interface,
+	.config			= b43_op_config,
+	.config_interface	= b43_op_config_interface,
+	.configure_filter	= b43_op_configure_filter,
+	.set_key		= b43_op_set_key,
+	.get_stats		= b43_op_get_stats,
+	.get_tx_stats		= b43_op_get_tx_stats,
+	.start			= b43_op_start,
+	.stop			= b43_op_stop,
+	.set_retry_limit	= b43_op_set_retry_limit,
+	.set_tim		= b43_op_beacon_set_tim,
+	.beacon_update		= b43_op_ibss_beacon_update,
 };
 
 /* Hard-reset the chip. Do not call this directly.
@@ -3605,79 +3811,26 @@ static void b43_chip_reset(struct work_struct *work)
 }
 
 static int b43_setup_modes(struct b43_wldev *dev,
-			   int have_aphy, int have_bphy, int have_gphy)
+			   bool have_2ghz_phy, bool have_5ghz_phy)
 {
 	struct ieee80211_hw *hw = dev->wl->hw;
-	struct ieee80211_hw_mode *mode;
 	struct b43_phy *phy = &dev->phy;
-	int cnt = 0;
-	int err;
 
-/*FIXME: Don't tell ieee80211 about an A-PHY, because we currently don't support A-PHY. */
-	have_aphy = 0;
-
-	phy->possible_phymodes = 0;
-	for (; 1; cnt++) {
-		if (have_aphy) {
-			B43_WARN_ON(cnt >= B43_MAX_PHYHWMODES);
-			mode = &phy->hwmodes[cnt];
-
-			mode->mode = MODE_IEEE80211A;
-			mode->num_channels = b43_a_chantable_size;
-			mode->channels = b43_a_chantable;
-			mode->num_rates = b43_a_ratetable_size;
-			mode->rates = b43_a_ratetable;
-			err = ieee80211_register_hwmode(hw, mode);
-			if (err)
-				return err;
-
-			phy->possible_phymodes |= B43_PHYMODE_A;
-			have_aphy = 0;
-			continue;
-		}
-		if (have_bphy) {
-			B43_WARN_ON(cnt >= B43_MAX_PHYHWMODES);
-			mode = &phy->hwmodes[cnt];
-
-			mode->mode = MODE_IEEE80211B;
-			mode->num_channels = b43_bg_chantable_size;
-			mode->channels = b43_bg_chantable;
-			mode->num_rates = b43_b_ratetable_size;
-			mode->rates = b43_b_ratetable;
-			err = ieee80211_register_hwmode(hw, mode);
-			if (err)
-				return err;
-
-			phy->possible_phymodes |= B43_PHYMODE_B;
-			have_bphy = 0;
-			continue;
-		}
-		if (have_gphy) {
-			B43_WARN_ON(cnt >= B43_MAX_PHYHWMODES);
-			mode = &phy->hwmodes[cnt];
-
-			mode->mode = MODE_IEEE80211G;
-			mode->num_channels = b43_bg_chantable_size;
-			mode->channels = b43_bg_chantable;
-			mode->num_rates = b43_g_ratetable_size;
-			mode->rates = b43_g_ratetable;
-			err = ieee80211_register_hwmode(hw, mode);
-			if (err)
-				return err;
-
-			phy->possible_phymodes |= B43_PHYMODE_G;
-			have_gphy = 0;
-			continue;
-		}
-		break;
-	}
+	/* XXX: This function will go away soon, when mac80211
+	 *      band stuff is rewritten. So this is just a hack.
+	 *      For now we always claim GPHY mode, as there is no
+	 *      support for NPHY and APHY in the device, yet.
+	 *      This assumption is OK, as any B, N or A PHY will already
+	 *      have died a horrible sanity check death earlier. */
+
+	hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &b43_band_2GHz;
+	phy->possible_phymodes |= B43_PHYMODE_G;
 
 	return 0;
 }
 
 static void b43_wireless_core_detach(struct b43_wldev *dev)
 {
-	b43_rfkill_free(dev);
 	/* We release firmware that late to not be required to re-request
 	 * is all the time when we reinit the core. */
 	b43_release_firmware(dev);
@@ -3689,7 +3842,7 @@ static int b43_wireless_core_attach(struct b43_wldev *dev)
 	struct ssb_bus *bus = dev->dev->bus;
 	struct pci_dev *pdev = bus->host_pci;
 	int err;
-	int have_aphy = 0, have_bphy = 0, have_gphy = 0;
+	bool have_2ghz_phy = 0, have_5ghz_phy = 0;
 	u32 tmp;
 
 	/* Do NOT do any device initialization here.
@@ -3709,17 +3862,12 @@ static int b43_wireless_core_attach(struct b43_wldev *dev)
 		u32 tmshigh;
 
 		tmshigh = ssb_read32(dev->dev, SSB_TMSHIGH);
-		have_aphy = !!(tmshigh & B43_TMSHIGH_APHY);
-		have_gphy = !!(tmshigh & B43_TMSHIGH_GPHY);
-		if (!have_aphy && !have_gphy)
-			have_bphy = 1;
-	} else if (dev->dev->id.revision == 4) {
-		have_gphy = 1;
-		have_aphy = 1;
+		have_2ghz_phy = !!(tmshigh & B43_TMSHIGH_HAVE_2GHZ_PHY);
+		have_5ghz_phy = !!(tmshigh & B43_TMSHIGH_HAVE_5GHZ_PHY);
 	} else
-		have_bphy = 1;
+		B43_WARN_ON(1);
 
-	dev->phy.gmode = (have_gphy || have_bphy);
+	dev->phy.gmode = have_2ghz_phy;
 	tmp = dev->phy.gmode ? B43_TMSLOW_GMODE : 0;
 	b43_wireless_core_reset(dev, tmp);
 
@@ -3731,31 +3879,34 @@ static int b43_wireless_core_attach(struct b43_wldev *dev)
 	    (pdev->device != 0x4312 &&
 	     pdev->device != 0x4319 && pdev->device != 0x4324)) {
 		/* No multiband support. */
-		have_aphy = 0;
-		have_bphy = 0;
-		have_gphy = 0;
+		have_2ghz_phy = 0;
+		have_5ghz_phy = 0;
 		switch (dev->phy.type) {
 		case B43_PHYTYPE_A:
-			have_aphy = 1;
-			break;
-		case B43_PHYTYPE_B:
-			have_bphy = 1;
+			have_5ghz_phy = 1;
 			break;
 		case B43_PHYTYPE_G:
-			have_gphy = 1;
+		case B43_PHYTYPE_N:
+			have_2ghz_phy = 1;
 			break;
 		default:
 			B43_WARN_ON(1);
 		}
 	}
-	dev->phy.gmode = (have_gphy || have_bphy);
+	if (dev->phy.type == B43_PHYTYPE_A) {
+		/* FIXME */
+		b43err(wl, "IEEE 802.11a devices are unsupported\n");
+		err = -EOPNOTSUPP;
+		goto err_powerdown;
+	}
+	dev->phy.gmode = have_2ghz_phy;
 	tmp = dev->phy.gmode ? B43_TMSLOW_GMODE : 0;
 	b43_wireless_core_reset(dev, tmp);
 
 	err = b43_validate_chipaccess(dev);
 	if (err)
 		goto err_powerdown;
-	err = b43_setup_modes(dev, have_aphy, have_bphy, have_gphy);
+	err = b43_setup_modes(dev, have_2ghz_phy, have_5ghz_phy);
 	if (err)
 		goto err_powerdown;
 
@@ -3763,7 +3914,6 @@ static int b43_wireless_core_attach(struct b43_wldev *dev)
 	if (!wl->current_dev)
 		wl->current_dev = dev;
 	INIT_WORK(&dev->restart_work, b43_chip_reset);
-	b43_rfkill_alloc(dev);
 
 	b43_radio_turn_off(dev, 1);
 	b43_switch_analog(dev, 0);
@@ -3827,8 +3977,6 @@ static int b43_one_core_attach(struct ssb_device *dev, struct b43_wl *wl)
 	tasklet_init(&wldev->isr_tasklet,
 		     (void (*)(unsigned long))b43_interrupt_tasklet,
 		     (unsigned long)wldev);
-	if (modparam_pio)
-		wldev->__using_pio = 1;
 	INIT_LIST_HEAD(&wldev->list);
 
 	err = b43_wireless_core_attach(wldev);
@@ -3853,20 +4001,10 @@ static void b43_sprom_fixup(struct ssb_bus *bus)
 	/* boardflags workarounds */
 	if (bus->boardinfo.vendor == SSB_BOARDVENDOR_DELL &&
 	    bus->chip_id == 0x4301 && bus->boardinfo.rev == 0x74)
-		bus->sprom.r1.boardflags_lo |= B43_BFL_BTCOEXIST;
+		bus->sprom.boardflags_lo |= B43_BFL_BTCOEXIST;
 	if (bus->boardinfo.vendor == PCI_VENDOR_ID_APPLE &&
 	    bus->boardinfo.type == 0x4E && bus->boardinfo.rev > 0x40)
-		bus->sprom.r1.boardflags_lo |= B43_BFL_PACTRL;
-
-	/* Handle case when gain is not set in sprom */
-	if (bus->sprom.r1.antenna_gain_a == 0xFF)
-		bus->sprom.r1.antenna_gain_a = 2;
-	if (bus->sprom.r1.antenna_gain_bg == 0xFF)
-		bus->sprom.r1.antenna_gain_bg = 2;
-
-	/* Convert Antennagain values to Q5.2 */
-	bus->sprom.r1.antenna_gain_a <<= 2;
-	bus->sprom.r1.antenna_gain_bg <<= 2;
+		bus->sprom.boardflags_lo |= B43_BFL_PACTRL;
 }
 
 static void b43_wireless_exit(struct ssb_device *dev, struct b43_wl *wl)
@@ -3893,16 +4031,17 @@ static int b43_wireless_init(struct ssb_device *dev)
 	}
 
 	/* fill hw info */
-	hw->flags = IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE;
+	hw->flags = IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE |
+		    IEEE80211_HW_RX_INCLUDES_FCS;
 	hw->max_signal = 100;
 	hw->max_rssi = -110;
 	hw->max_noise = -110;
 	hw->queues = 1;		/* FIXME: hardware has more queues */
 	SET_IEEE80211_DEV(hw, dev->dev);
-	if (is_valid_ether_addr(sprom->r1.et1mac))
-		SET_IEEE80211_PERM_ADDR(hw, sprom->r1.et1mac);
+	if (is_valid_ether_addr(sprom->et1mac))
+		SET_IEEE80211_PERM_ADDR(hw, sprom->et1mac);
 	else
-		SET_IEEE80211_PERM_ADDR(hw, sprom->r1.il0mac);
+		SET_IEEE80211_PERM_ADDR(hw, sprom->il0mac);
 
 	/* Get and initialize struct b43_wl */
 	wl = hw_to_b43_wl(hw);
@@ -3910,6 +4049,7 @@ static int b43_wireless_init(struct ssb_device *dev)
 	wl->hw = hw;
 	spin_lock_init(&wl->irq_lock);
 	spin_lock_init(&wl->leds_lock);
+	spin_lock_init(&wl->shm_lock);
 	mutex_init(&wl->mutex);
 	INIT_LIST_HEAD(&wl->devlist);
 
@@ -4053,16 +4193,6 @@ static struct ssb_driver b43_ssb_driver = {
 	.resume		= b43_resume,
 };
 
-inline int b43_pci_ssb_bridge_init(void)
-{
-	return ssb_pcihost_register(&b43_pci_bridge_driver);
-}
-
-inline void b43_pci_ssb_bridge_exit(void)
-{
-	ssb_pcihost_unregister(&b43_pci_bridge_driver);
-}
-
 static int __init b43_init(void)
 {
 	int err;
@@ -4071,19 +4201,12 @@ static int __init b43_init(void)
 	err = b43_pcmcia_init();
 	if (err)
 		goto err_dfs_exit;
-
-	err = b43_pci_ssb_bridge_init();
-	if (err)
-		goto err_pcmcia_exit;
-
 	err = ssb_driver_register(&b43_ssb_driver);
 	if (err)
-		goto err_pci_exit;
+		goto err_pcmcia_exit;
 
 	return err;
 
-err_pci_exit:
-	b43_pci_ssb_bridge_exit();
 err_pcmcia_exit:
 	b43_pcmcia_exit();
 err_dfs_exit:
@@ -4094,7 +4217,6 @@ err_dfs_exit:
 static void __exit b43_exit(void)
 {
 	ssb_driver_unregister(&b43_ssb_driver);
-	b43_pci_ssb_bridge_exit();
 	b43_pcmcia_exit();
 	b43_debugfs_exit();
 }
diff --git a/package/b43/src/main.h b/package/b43/src/main.h
index 284d17da17..2d52d9de93 100644
--- a/package/b43/src/main.h
+++ b/package/b43/src/main.h
@@ -3,7 +3,7 @@
   Broadcom B43 wireless driver
 
   Copyright (c) 2005 Martin Langer <martin-langer@gmx.de>,
-                     Stefano Brivio <st3@riseup.net>
+                     Stefano Brivio <stefano.brivio@polimi.it>
                      Michael Buesch <mb@bu3sch.de>
                      Danny van Dyk <kugelfang@gentoo.org>
                      Andreas Jaggi <andreas.jaggi@waterwave.ch>
@@ -39,11 +39,11 @@
 #define PAD_BYTES(nr_bytes)		P4D_BYTES( __LINE__ , (nr_bytes))
 
 /* Lightweight function to convert a frequency (in Mhz) to a channel number. */
-static inline u8 b43_freq_to_channel_a(int freq)
+static inline u8 b43_freq_to_channel_5ghz(int freq)
 {
 	return ((freq - 5000) / 5);
 }
-static inline u8 b43_freq_to_channel_bg(int freq)
+static inline u8 b43_freq_to_channel_2ghz(int freq)
 {
 	u8 channel;
 
@@ -54,19 +54,13 @@ static inline u8 b43_freq_to_channel_bg(int freq)
 
 	return channel;
 }
-static inline u8 b43_freq_to_channel(struct b43_wldev *dev, int freq)
-{
-	if (dev->phy.type == B43_PHYTYPE_A)
-		return b43_freq_to_channel_a(freq);
-	return b43_freq_to_channel_bg(freq);
-}
 
 /* Lightweight function to convert a channel number to a frequency (in Mhz). */
-static inline int b43_channel_to_freq_a(u8 channel)
+static inline int b43_channel_to_freq_5ghz(u8 channel)
 {
 	return (5000 + (5 * channel));
 }
-static inline int b43_channel_to_freq_bg(u8 channel)
+static inline int b43_channel_to_freq_2ghz(u8 channel)
 {
 	int freq;
 
@@ -77,12 +71,6 @@ static inline int b43_channel_to_freq_bg(u8 channel)
 
 	return freq;
 }
-static inline int b43_channel_to_freq(struct b43_wldev *dev, u8 channel)
-{
-	if (dev->phy.type == B43_PHYTYPE_A)
-		return b43_channel_to_freq_a(channel);
-	return b43_channel_to_freq_bg(channel);
-}
 
 static inline int b43_is_cck_rate(int rate)
 {
@@ -96,6 +84,9 @@ static inline int b43_is_ofdm_rate(int rate)
 	return !b43_is_cck_rate(rate);
 }
 
+u8 b43_ieee80211_antenna_sanitize(struct b43_wldev *dev,
+				  u8 antenna_nr);
+
 void b43_tsf_read(struct b43_wldev *dev, u64 * tsf);
 void b43_tsf_write(struct b43_wldev *dev, u64 tsf);
 
diff --git a/package/b43/src/nphy.c b/package/b43/src/nphy.c
new file mode 100644
index 0000000000..705131ef4b
--- /dev/null
+++ b/package/b43/src/nphy.c
@@ -0,0 +1,489 @@
+/*
+
+  Broadcom B43 wireless driver
+  IEEE 802.11n PHY support
+
+  Copyright (c) 2008 Michael Buesch <mb@bu3sch.de>
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 of the License, or
+  (at your option) any later version.
+
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program; see the file COPYING.  If not, write to
+  the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
+  Boston, MA 02110-1301, USA.
+
+*/
+
+#include <linux/delay.h>
+#include <linux/types.h>
+
+#include "b43.h"
+#include "nphy.h"
+#include "tables_nphy.h"
+
+#include <linux/delay.h>
+
+
+void b43_nphy_set_rxantenna(struct b43_wldev *dev, int antenna)
+{//TODO
+}
+
+void b43_nphy_xmitpower(struct b43_wldev *dev)
+{//TODO
+}
+
+static void b43_chantab_radio_upload(struct b43_wldev *dev,
+				     const struct b43_nphy_channeltab_entry *e)
+{
+	b43_radio_write16(dev, B2055_PLL_REF, e->radio_pll_ref);
+	b43_radio_write16(dev, B2055_RF_PLLMOD0, e->radio_rf_pllmod0);
+	b43_radio_write16(dev, B2055_RF_PLLMOD1, e->radio_rf_pllmod1);
+	b43_radio_write16(dev, B2055_VCO_CAPTAIL, e->radio_vco_captail);
+	b43_radio_write16(dev, B2055_VCO_CAL1, e->radio_vco_cal1);
+	b43_radio_write16(dev, B2055_VCO_CAL2, e->radio_vco_cal2);
+	b43_radio_write16(dev, B2055_PLL_LFC1, e->radio_pll_lfc1);
+	b43_radio_write16(dev, B2055_PLL_LFR1, e->radio_pll_lfr1);
+	b43_radio_write16(dev, B2055_PLL_LFC2, e->radio_pll_lfc2);
+	b43_radio_write16(dev, B2055_LGBUF_CENBUF, e->radio_lgbuf_cenbuf);
+	b43_radio_write16(dev, B2055_LGEN_TUNE1, e->radio_lgen_tune1);
+	b43_radio_write16(dev, B2055_LGEN_TUNE2, e->radio_lgen_tune2);
+	b43_radio_write16(dev, B2055_C1_LGBUF_ATUNE, e->radio_c1_lgbuf_atune);
+	b43_radio_write16(dev, B2055_C1_LGBUF_GTUNE, e->radio_c1_lgbuf_gtune);
+	b43_radio_write16(dev, B2055_C1_RX_RFR1, e->radio_c1_rx_rfr1);
+	b43_radio_write16(dev, B2055_C1_TX_PGAPADTN, e->radio_c1_tx_pgapadtn);
+	b43_radio_write16(dev, B2055_C1_TX_MXBGTRIM, e->radio_c1_tx_mxbgtrim);
+	b43_radio_write16(dev, B2055_C2_LGBUF_ATUNE, e->radio_c2_lgbuf_atune);
+	b43_radio_write16(dev, B2055_C2_LGBUF_GTUNE, e->radio_c2_lgbuf_gtune);
+	b43_radio_write16(dev, B2055_C2_RX_RFR1, e->radio_c2_rx_rfr1);
+	b43_radio_write16(dev, B2055_C2_TX_PGAPADTN, e->radio_c2_tx_pgapadtn);
+	b43_radio_write16(dev, B2055_C2_TX_MXBGTRIM, e->radio_c2_tx_mxbgtrim);
+}
+
+static void b43_chantab_phy_upload(struct b43_wldev *dev,
+				   const struct b43_nphy_channeltab_entry *e)
+{
+	b43_phy_write(dev, B43_NPHY_BW1A, e->phy_bw1a);
+	b43_phy_write(dev, B43_NPHY_BW2, e->phy_bw2);
+	b43_phy_write(dev, B43_NPHY_BW3, e->phy_bw3);
+	b43_phy_write(dev, B43_NPHY_BW4, e->phy_bw4);
+	b43_phy_write(dev, B43_NPHY_BW5, e->phy_bw5);
+	b43_phy_write(dev, B43_NPHY_BW6, e->phy_bw6);
+}
+
+static void b43_nphy_tx_power_fix(struct b43_wldev *dev)
+{
+	//TODO
+}
+
+/* Tune the hardware to a new channel. Don't call this directly.
+ * Use b43_radio_selectchannel() */
+int b43_nphy_selectchannel(struct b43_wldev *dev, u8 channel)
+{
+	const struct b43_nphy_channeltab_entry *tabent;
+
+	tabent = b43_nphy_get_chantabent(dev, channel);
+	if (!tabent)
+		return -ESRCH;
+
+	//FIXME enable/disable band select upper20 in RXCTL
+	if (0 /*FIXME 5Ghz*/)
+		b43_radio_maskset(dev, B2055_MASTER1, 0xFF8F, 0x20);
+	else
+		b43_radio_maskset(dev, B2055_MASTER1, 0xFF8F, 0x50);
+	b43_chantab_radio_upload(dev, tabent);
+	udelay(50);
+	b43_radio_write16(dev, B2055_VCO_CAL10, 5);
+	b43_radio_write16(dev, B2055_VCO_CAL10, 45);
+	b43_radio_write16(dev, B2055_VCO_CAL10, 65);
+	udelay(300);
+	if (0 /*FIXME 5Ghz*/)
+		b43_phy_set(dev, B43_NPHY_BANDCTL, B43_NPHY_BANDCTL_5GHZ);
+	else
+		b43_phy_mask(dev, B43_NPHY_BANDCTL, ~B43_NPHY_BANDCTL_5GHZ);
+	b43_chantab_phy_upload(dev, tabent);
+	b43_nphy_tx_power_fix(dev);
+
+	return 0;
+}
+
+static void b43_radio_init2055_pre(struct b43_wldev *dev)
+{
+	b43_phy_mask(dev, B43_NPHY_RFCTL_CMD,
+		     ~B43_NPHY_RFCTL_CMD_PORFORCE);
+	b43_phy_set(dev, B43_NPHY_RFCTL_CMD,
+		    B43_NPHY_RFCTL_CMD_CHIP0PU |
+		    B43_NPHY_RFCTL_CMD_OEPORFORCE);
+	b43_phy_set(dev, B43_NPHY_RFCTL_CMD,
+		    B43_NPHY_RFCTL_CMD_PORFORCE);
+}
+
+static void b43_radio_init2055_post(struct b43_wldev *dev)
+{
+	struct ssb_sprom *sprom = &(dev->dev->bus->sprom);
+	struct ssb_boardinfo *binfo = &(dev->dev->bus->boardinfo);
+	int i;
+	u16 val;
+
+	b43_radio_mask(dev, B2055_MASTER1, 0xFFF3);
+	msleep(1);
+	if ((sprom->revision != 4) || !(sprom->boardflags_hi & 0x0002)) {
+		if ((binfo->vendor != PCI_VENDOR_ID_BROADCOM) ||
+		    (binfo->type != 0x46D) ||
+		    (binfo->rev < 0x41)) {
+			b43_radio_mask(dev, B2055_C1_RX_BB_REG, 0x7F);
+			b43_radio_mask(dev, B2055_C1_RX_BB_REG, 0x7F);
+			msleep(1);
+		}
+	}
+	b43_radio_maskset(dev, B2055_RRCCAL_NOPTSEL, 0x3F, 0x2C);
+	msleep(1);
+	b43_radio_write16(dev, B2055_CAL_MISC, 0x3C);
+	msleep(1);
+	b43_radio_mask(dev, B2055_CAL_MISC, 0xFFBE);
+	msleep(1);
+	b43_radio_set(dev, B2055_CAL_LPOCTL, 0x80);
+	msleep(1);
+	b43_radio_set(dev, B2055_CAL_MISC, 0x1);
+	msleep(1);
+	b43_radio_set(dev, B2055_CAL_MISC, 0x40);
+	msleep(1);
+	for (i = 0; i < 100; i++) {
+		val = b43_radio_read16(dev, B2055_CAL_COUT2);
+		if (val & 0x80)
+			break;
+		udelay(10);
+	}
+	msleep(1);
+	b43_radio_mask(dev, B2055_CAL_LPOCTL, 0xFF7F);
+	msleep(1);
+	b43_radio_selectchannel(dev, dev->phy.channel, 0);
+	b43_radio_write16(dev, B2055_C1_RX_BB_LPF, 0x9);
+	b43_radio_write16(dev, B2055_C2_RX_BB_LPF, 0x9);
+	b43_radio_write16(dev, B2055_C1_RX_BB_MIDACHP, 0x83);
+	b43_radio_write16(dev, B2055_C2_RX_BB_MIDACHP, 0x83);
+}
+
+/* Initialize a Broadcom 2055 N-radio */
+static void b43_radio_init2055(struct b43_wldev *dev)
+{
+	b43_radio_init2055_pre(dev);
+	if (b43_status(dev) < B43_STAT_INITIALIZED)
+		b2055_upload_inittab(dev, 0, 1);
+	else
+		b2055_upload_inittab(dev, 0/*FIXME on 5ghz band*/, 0);
+	b43_radio_init2055_post(dev);
+}
+
+void b43_nphy_radio_turn_on(struct b43_wldev *dev)
+{
+	b43_radio_init2055(dev);
+}
+
+void b43_nphy_radio_turn_off(struct b43_wldev *dev)
+{
+	b43_phy_mask(dev, B43_NPHY_RFCTL_CMD,
+		     ~B43_NPHY_RFCTL_CMD_EN);
+}
+
+#define ntab_upload(dev, offset, data) do { \
+		unsigned int i;						\
+		for (i = 0; i < (offset##_SIZE); i++)			\
+			b43_ntab_write(dev, (offset) + i, (data)[i]);	\
+	} while (0)
+
+/* Upload the N-PHY tables. */
+static void b43_nphy_tables_init(struct b43_wldev *dev)
+{
+	/* Static tables */
+	ntab_upload(dev, B43_NTAB_FRAMESTRUCT, b43_ntab_framestruct);
+	ntab_upload(dev, B43_NTAB_FRAMELT, b43_ntab_framelookup);
+	ntab_upload(dev, B43_NTAB_TMAP, b43_ntab_tmap);
+	ntab_upload(dev, B43_NTAB_TDTRN, b43_ntab_tdtrn);
+	ntab_upload(dev, B43_NTAB_INTLEVEL, b43_ntab_intlevel);
+	ntab_upload(dev, B43_NTAB_PILOT, b43_ntab_pilot);
+	ntab_upload(dev, B43_NTAB_PILOTLT, b43_ntab_pilotlt);
+	ntab_upload(dev, B43_NTAB_TDI20A0, b43_ntab_tdi20a0);
+	ntab_upload(dev, B43_NTAB_TDI20A1, b43_ntab_tdi20a1);
+	ntab_upload(dev, B43_NTAB_TDI40A0, b43_ntab_tdi40a0);
+	ntab_upload(dev, B43_NTAB_TDI40A1, b43_ntab_tdi40a1);
+	ntab_upload(dev, B43_NTAB_BDI, b43_ntab_bdi);
+	ntab_upload(dev, B43_NTAB_CHANEST, b43_ntab_channelest);
+	ntab_upload(dev, B43_NTAB_MCS, b43_ntab_mcs);
+
+	/* Volatile tables */
+	ntab_upload(dev, B43_NTAB_NOISEVAR10, b43_ntab_noisevar10);
+	ntab_upload(dev, B43_NTAB_NOISEVAR11, b43_ntab_noisevar11);
+	ntab_upload(dev, B43_NTAB_C0_ESTPLT, b43_ntab_estimatepowerlt0);
+	ntab_upload(dev, B43_NTAB_C1_ESTPLT, b43_ntab_estimatepowerlt1);
+	ntab_upload(dev, B43_NTAB_C0_ADJPLT, b43_ntab_adjustpower0);
+	ntab_upload(dev, B43_NTAB_C1_ADJPLT, b43_ntab_adjustpower1);
+	ntab_upload(dev, B43_NTAB_C0_GAINCTL, b43_ntab_gainctl0);
+	ntab_upload(dev, B43_NTAB_C1_GAINCTL, b43_ntab_gainctl1);
+	ntab_upload(dev, B43_NTAB_C0_IQLT, b43_ntab_iqlt0);
+	ntab_upload(dev, B43_NTAB_C1_IQLT, b43_ntab_iqlt1);
+	ntab_upload(dev, B43_NTAB_C0_LOFEEDTH, b43_ntab_loftlt0);
+	ntab_upload(dev, B43_NTAB_C1_LOFEEDTH, b43_ntab_loftlt1);
+}
+
+static void b43_nphy_workarounds(struct b43_wldev *dev)
+{
+	struct b43_phy *phy = &dev->phy;
+	unsigned int i;
+
+	b43_phy_set(dev, B43_NPHY_IQFLIP,
+		    B43_NPHY_IQFLIP_ADC1 | B43_NPHY_IQFLIP_ADC2);
+	//FIXME the following condition is different in the specs.
+	if (1 /* FIXME band is 2.4GHz */) {
+		b43_phy_set(dev, B43_NPHY_CLASSCTL,
+			    B43_NPHY_CLASSCTL_CCKEN);
+	} else {
+		b43_phy_mask(dev, B43_NPHY_CLASSCTL,
+			     ~B43_NPHY_CLASSCTL_CCKEN);
+	}
+	b43_radio_set(dev, B2055_C1_TX_RF_SPARE, 0x8);
+	b43_phy_write(dev, B43_NPHY_TXFRAMEDELAY, 8);
+
+	/* Fixup some tables */
+	b43_ntab_write(dev, B43_NTAB16(8, 0x00), 0xA);
+	b43_ntab_write(dev, B43_NTAB16(8, 0x10), 0xA);
+	b43_ntab_write(dev, B43_NTAB16(8, 0x02), 0xCDAA);
+	b43_ntab_write(dev, B43_NTAB16(8, 0x12), 0xCDAA);
+	b43_ntab_write(dev, B43_NTAB16(8, 0x08), 0);
+	b43_ntab_write(dev, B43_NTAB16(8, 0x18), 0);
+	b43_ntab_write(dev, B43_NTAB16(8, 0x07), 0x7AAB);
+	b43_ntab_write(dev, B43_NTAB16(8, 0x17), 0x7AAB);
+	b43_ntab_write(dev, B43_NTAB16(8, 0x06), 0x800);
+	b43_ntab_write(dev, B43_NTAB16(8, 0x16), 0x800);
+
+	b43_phy_write(dev, B43_NPHY_RFCTL_LUT_TRSW_LO1, 0x2D8);
+	b43_phy_write(dev, B43_NPHY_RFCTL_LUT_TRSW_UP1, 0x301);
+	b43_phy_write(dev, B43_NPHY_RFCTL_LUT_TRSW_LO2, 0x2D8);
+	b43_phy_write(dev, B43_NPHY_RFCTL_LUT_TRSW_UP2, 0x301);
+
+	//TODO set RF sequence
+
+	/* Set narrowband clip threshold */
+	b43_phy_write(dev, B43_NPHY_C1_NBCLIPTHRES, 66);
+	b43_phy_write(dev, B43_NPHY_C2_NBCLIPTHRES, 66);
+
+	/* Set wideband clip 2 threshold */
+	b43_phy_maskset(dev, B43_NPHY_C1_CLIPWBTHRES,
+			~B43_NPHY_C1_CLIPWBTHRES_CLIP2,
+			21 << B43_NPHY_C1_CLIPWBTHRES_CLIP2_SHIFT);
+	b43_phy_maskset(dev, B43_NPHY_C2_CLIPWBTHRES,
+			~B43_NPHY_C2_CLIPWBTHRES_CLIP2,
+			21 << B43_NPHY_C2_CLIPWBTHRES_CLIP2_SHIFT);
+
+	/* Set Clip 2 detect */
+	b43_phy_set(dev, B43_NPHY_C1_CGAINI,
+		    B43_NPHY_C1_CGAINI_CL2DETECT);
+	b43_phy_set(dev, B43_NPHY_C2_CGAINI,
+		    B43_NPHY_C2_CGAINI_CL2DETECT);
+
+	if (0 /*FIXME*/) {
+		/* Set dwell lengths */
+		b43_phy_write(dev, B43_NPHY_CLIP1_NBDWELL_LEN, 43);
+		b43_phy_write(dev, B43_NPHY_CLIP2_NBDWELL_LEN, 43);
+		b43_phy_write(dev, B43_NPHY_W1CLIP1_DWELL_LEN, 9);
+		b43_phy_write(dev, B43_NPHY_W1CLIP2_DWELL_LEN, 9);
+
+		/* Set gain backoff */
+		b43_phy_maskset(dev, B43_NPHY_C1_CGAINI,
+				~B43_NPHY_C1_CGAINI_GAINBKOFF,
+				1 << B43_NPHY_C1_CGAINI_GAINBKOFF_SHIFT);
+		b43_phy_maskset(dev, B43_NPHY_C2_CGAINI,
+				~B43_NPHY_C2_CGAINI_GAINBKOFF,
+				1 << B43_NPHY_C2_CGAINI_GAINBKOFF_SHIFT);
+
+		/* Set HPVGA2 index */
+		b43_phy_maskset(dev, B43_NPHY_C1_INITGAIN,
+				~B43_NPHY_C1_INITGAIN_HPVGA2,
+				6 << B43_NPHY_C1_INITGAIN_HPVGA2_SHIFT);
+		b43_phy_maskset(dev, B43_NPHY_C2_INITGAIN,
+				~B43_NPHY_C2_INITGAIN_HPVGA2,
+				6 << B43_NPHY_C2_INITGAIN_HPVGA2_SHIFT);
+
+		//FIXME verify that the specs really mean to use autoinc here.
+		for (i = 0; i < 3; i++)
+			b43_ntab_write(dev, B43_NTAB16(7, 0x106) + i, 0x673);
+	}
+
+	/* Set minimum gain value */
+	b43_phy_maskset(dev, B43_NPHY_C1_MINMAX_GAIN,
+			~B43_NPHY_C1_MINGAIN,
+			23 << B43_NPHY_C1_MINGAIN_SHIFT);
+	b43_phy_maskset(dev, B43_NPHY_C2_MINMAX_GAIN,
+			~B43_NPHY_C2_MINGAIN,
+			23 << B43_NPHY_C2_MINGAIN_SHIFT);
+
+	if (phy->rev < 2) {
+		b43_phy_mask(dev, B43_NPHY_SCRAM_SIGCTL,
+			     ~B43_NPHY_SCRAM_SIGCTL_SCM);
+	}
+
+	/* Set phase track alpha and beta */
+	b43_phy_write(dev, B43_NPHY_PHASETR_A0, 0x125);
+	b43_phy_write(dev, B43_NPHY_PHASETR_A1, 0x1B3);
+	b43_phy_write(dev, B43_NPHY_PHASETR_A2, 0x105);
+	b43_phy_write(dev, B43_NPHY_PHASETR_B0, 0x16E);
+	b43_phy_write(dev, B43_NPHY_PHASETR_B1, 0xCD);
+	b43_phy_write(dev, B43_NPHY_PHASETR_B2, 0x20);
+}
+
+static void b43_nphy_reset_cca(struct b43_wldev *dev)
+{
+	u16 bbcfg;
+
+	ssb_write32(dev->dev, SSB_TMSLOW,
+		    ssb_read32(dev->dev, SSB_TMSLOW) | SSB_TMSLOW_FGC);
+	bbcfg = b43_phy_read(dev, B43_NPHY_BBCFG);
+	b43_phy_set(dev, B43_NPHY_BBCFG, B43_NPHY_BBCFG_RSTCCA);
+	b43_phy_write(dev, B43_NPHY_BBCFG,
+		      bbcfg & ~B43_NPHY_BBCFG_RSTCCA);
+	ssb_write32(dev->dev, SSB_TMSLOW,
+		    ssb_read32(dev->dev, SSB_TMSLOW) & ~SSB_TMSLOW_FGC);
+}
+
+enum b43_nphy_rf_sequence {
+	B43_RFSEQ_RX2TX,
+	B43_RFSEQ_TX2RX,
+	B43_RFSEQ_RESET2RX,
+	B43_RFSEQ_UPDATE_GAINH,
+	B43_RFSEQ_UPDATE_GAINL,
+	B43_RFSEQ_UPDATE_GAINU,
+};
+
+static void b43_nphy_force_rf_sequence(struct b43_wldev *dev,
+				       enum b43_nphy_rf_sequence seq)
+{
+	static const u16 trigger[] = {
+		[B43_RFSEQ_RX2TX]		= B43_NPHY_RFSEQTR_RX2TX,
+		[B43_RFSEQ_TX2RX]		= B43_NPHY_RFSEQTR_TX2RX,
+		[B43_RFSEQ_RESET2RX]		= B43_NPHY_RFSEQTR_RST2RX,
+		[B43_RFSEQ_UPDATE_GAINH]	= B43_NPHY_RFSEQTR_UPGH,
+		[B43_RFSEQ_UPDATE_GAINL]	= B43_NPHY_RFSEQTR_UPGL,
+		[B43_RFSEQ_UPDATE_GAINU]	= B43_NPHY_RFSEQTR_UPGU,
+	};
+	int i;
+
+	B43_WARN_ON(seq >= ARRAY_SIZE(trigger));
+
+	b43_phy_set(dev, B43_NPHY_RFSEQMODE,
+		    B43_NPHY_RFSEQMODE_CAOVER | B43_NPHY_RFSEQMODE_TROVER);
+	b43_phy_set(dev, B43_NPHY_RFSEQTR, trigger[seq]);
+	for (i = 0; i < 200; i++) {
+		if (!(b43_phy_read(dev, B43_NPHY_RFSEQST) & trigger[seq]))
+			goto ok;
+		msleep(1);
+	}
+	b43err(dev->wl, "RF sequence status timeout\n");
+ok:
+	b43_phy_mask(dev, B43_NPHY_RFSEQMODE,
+		     ~(B43_NPHY_RFSEQMODE_CAOVER | B43_NPHY_RFSEQMODE_TROVER));
+}
+
+static void b43_nphy_bphy_init(struct b43_wldev *dev)
+{
+	unsigned int i;
+	u16 val;
+
+	val = 0x1E1F;
+	for (i = 0; i < 14; i++) {
+		b43_phy_write(dev, B43_PHY_N_BMODE(0x88 + i), val);
+		val -= 0x202;
+	}
+	val = 0x3E3F;
+	for (i = 0; i < 16; i++) {
+		b43_phy_write(dev, B43_PHY_N_BMODE(0x97 + i), val);
+		val -= 0x202;
+	}
+	b43_phy_write(dev, B43_PHY_N_BMODE(0x38), 0x668);
+}
+
+/* RSSI Calibration */
+static void b43_nphy_rssi_cal(struct b43_wldev *dev, u8 type)
+{
+	//TODO
+}
+
+int b43_phy_initn(struct b43_wldev *dev)
+{
+	struct b43_phy *phy = &dev->phy;
+	u16 tmp;
+
+	//TODO: Spectral management
+	b43_nphy_tables_init(dev);
+
+	/* Clear all overrides */
+	b43_phy_write(dev, B43_NPHY_RFCTL_OVER, 0);
+	b43_phy_write(dev, B43_NPHY_RFCTL_INTC1, 0);
+	b43_phy_write(dev, B43_NPHY_RFCTL_INTC2, 0);
+	b43_phy_write(dev, B43_NPHY_RFCTL_INTC3, 0);
+	b43_phy_write(dev, B43_NPHY_RFCTL_INTC4, 0);
+	b43_phy_mask(dev, B43_NPHY_RFSEQMODE,
+		     ~(B43_NPHY_RFSEQMODE_CAOVER |
+		       B43_NPHY_RFSEQMODE_TROVER));
+	b43_phy_write(dev, B43_NPHY_AFECTL_OVER, 0);
+
+	tmp = (phy->rev < 2) ? 64 : 59;
+	b43_phy_maskset(dev, B43_NPHY_BPHY_CTL3,
+			~B43_NPHY_BPHY_CTL3_SCALE,
+			tmp << B43_NPHY_BPHY_CTL3_SCALE_SHIFT);
+
+	b43_phy_write(dev, B43_NPHY_AFESEQ_TX2RX_PUD_20M, 0x20);
+	b43_phy_write(dev, B43_NPHY_AFESEQ_TX2RX_PUD_40M, 0x20);
+
+	b43_phy_write(dev, B43_NPHY_TXREALFD, 184);
+	b43_phy_write(dev, B43_NPHY_MIMO_CRSTXEXT, 200);
+	b43_phy_write(dev, B43_NPHY_PLOAD_CSENSE_EXTLEN, 80);
+	b43_phy_write(dev, B43_NPHY_C2_BCLIPBKOFF, 511);
+
+	//TODO MIMO-Config
+	//TODO Update TX/RX chain
+
+	if (phy->rev < 2) {
+		b43_phy_write(dev, B43_NPHY_DUP40_GFBL, 0xAA8);
+		b43_phy_write(dev, B43_NPHY_DUP40_BL, 0x9A4);
+	}
+	b43_nphy_workarounds(dev);
+	b43_nphy_reset_cca(dev);
+
+	ssb_write32(dev->dev, SSB_TMSLOW,
+		    ssb_read32(dev->dev, SSB_TMSLOW) | B43_TMSLOW_MACPHYCLKEN);
+	b43_nphy_force_rf_sequence(dev, B43_RFSEQ_RX2TX);
+	b43_nphy_force_rf_sequence(dev, B43_RFSEQ_RESET2RX);
+
+	b43_phy_read(dev, B43_NPHY_CLASSCTL); /* dummy read */
+	//TODO read core1/2 clip1 thres regs
+
+	if (1 /* FIXME Band is 2.4GHz */)
+		b43_nphy_bphy_init(dev);
+	//TODO disable TX power control
+	//TODO Fix the TX power settings
+	//TODO Init periodic calibration with reason 3
+	b43_nphy_rssi_cal(dev, 2);
+	b43_nphy_rssi_cal(dev, 0);
+	b43_nphy_rssi_cal(dev, 1);
+	//TODO get TX gain
+	//TODO init superswitch
+	//TODO calibrate LO
+	//TODO idle TSSI TX pctl
+	//TODO TX power control power setup
+	//TODO table writes
+	//TODO TX power control coefficients
+	//TODO enable TX power control
+	//TODO control antenna selection
+	//TODO init radar detection
+	//TODO reset channel if changed
+
+	b43err(dev->wl, "IEEE 802.11n devices are not supported, yet.\n");
+	return 0;
+}
diff --git a/package/b43/src/nphy.h b/package/b43/src/nphy.h
new file mode 100644
index 0000000000..5d95118b81
--- /dev/null
+++ b/package/b43/src/nphy.h
@@ -0,0 +1,932 @@
+#ifndef B43_NPHY_H_
+#define B43_NPHY_H_
+
+#include "phy.h"
+
+
+/* N-PHY registers. */
+
+#define B43_NPHY_BBCFG				B43_PHY_N(0x001) /* BB config */
+#define  B43_NPHY_BBCFG_RSTCCA			0x4000 /* Reset CCA */
+#define  B43_NPHY_BBCFG_RSTRX			0x8000 /* Reset RX */
+#define B43_NPHY_CHANNEL			B43_PHY_N(0x005) /* Channel */
+#define B43_NPHY_TXERR				B43_PHY_N(0x007) /* TX error */
+#define B43_NPHY_BANDCTL			B43_PHY_N(0x009) /* Band control */
+#define  B43_NPHY_BANDCTL_5GHZ			0x0001 /* Use the 5GHz band */
+#define B43_NPHY_4WI_ADDR			B43_PHY_N(0x00B) /* Four-wire bus address */
+#define B43_NPHY_4WI_DATAHI			B43_PHY_N(0x00C) /* Four-wire bus data high */
+#define B43_NPHY_4WI_DATALO			B43_PHY_N(0x00D) /* Four-wire bus data low */
+#define B43_NPHY_BIST_STAT0			B43_PHY_N(0x00E) /* Built-in self test status 0 */
+#define B43_NPHY_BIST_STAT1			B43_PHY_N(0x00F) /* Built-in self test status 1 */
+
+#define B43_NPHY_C1_DESPWR			B43_PHY_N(0x018) /* Core 1 desired power */
+#define B43_NPHY_C1_CCK_DESPWR			B43_PHY_N(0x019) /* Core 1 CCK desired power */
+#define B43_NPHY_C1_BCLIPBKOFF			B43_PHY_N(0x01A) /* Core 1 barely clip backoff */
+#define B43_NPHY_C1_CCK_BCLIPBKOFF		B43_PHY_N(0x01B) /* Core 1 CCK barely clip backoff */
+#define B43_NPHY_C1_CGAINI			B43_PHY_N(0x01C) /* Core 1 compute gain info */
+#define  B43_NPHY_C1_CGAINI_GAINBKOFF		0x001F /* Gain backoff */
+#define  B43_NPHY_C1_CGAINI_GAINBKOFF_SHIFT	0
+#define  B43_NPHY_C1_CGAINI_CLIPGBKOFF		0x03E0 /* Clip gain backoff */
+#define  B43_NPHY_C1_CGAINI_CLIPGBKOFF_SHIFT	5
+#define  B43_NPHY_C1_CGAINI_GAINSTEP		0x1C00 /* Gain step */
+#define  B43_NPHY_C1_CGAINI_GAINSTEP_SHIFT	10
+#define  B43_NPHY_C1_CGAINI_CL2DETECT		0x2000 /* Clip 2 detect mask */
+#define B43_NPHY_C1_CCK_CGAINI			B43_PHY_N(0x01D) /* Core 1 CCK compute gain info */
+#define  B43_NPHY_C1_CCK_CGAINI_GAINBKOFF	0x001F /* Gain backoff */
+#define  B43_NPHY_C1_CCK_CGAINI_CLIPGBKOFF	0x01E0 /* CCK barely clip gain backoff */
+#define B43_NPHY_C1_MINMAX_GAIN			B43_PHY_N(0x01E) /* Core 1 min/max gain */
+#define  B43_NPHY_C1_MINGAIN			0x00FF /* Minimum gain */
+#define  B43_NPHY_C1_MINGAIN_SHIFT		0
+#define  B43_NPHY_C1_MAXGAIN			0xFF00 /* Maximum gain */
+#define  B43_NPHY_C1_MAXGAIN_SHIFT		8
+#define B43_NPHY_C1_CCK_MINMAX_GAIN		B43_PHY_N(0x01F) /* Core 1 CCK min/max gain */
+#define  B43_NPHY_C1_CCK_MINGAIN		0x00FF /* Minimum gain */
+#define  B43_NPHY_C1_CCK_MINGAIN_SHIFT		0
+#define  B43_NPHY_C1_CCK_MAXGAIN		0xFF00 /* Maximum gain */
+#define  B43_NPHY_C1_CCK_MAXGAIN_SHIFT		8
+#define B43_NPHY_C1_INITGAIN			B43_PHY_N(0x020) /* Core 1 initial gain code */
+#define  B43_NPHY_C1_INITGAIN_EXTLNA		0x0001 /* External LNA index */
+#define  B43_NPHY_C1_INITGAIN_LNA		0x0006 /* LNA index */
+#define  B43_NPHY_C1_INITGAIN_LNAIDX_SHIFT	1
+#define  B43_NPHY_C1_INITGAIN_HPVGA1		0x0078 /* HPVGA1 index */
+#define  B43_NPHY_C1_INITGAIN_HPVGA1_SHIFT	3
+#define  B43_NPHY_C1_INITGAIN_HPVGA2		0x0F80 /* HPVGA2 index */
+#define  B43_NPHY_C1_INITGAIN_HPVGA2_SHIFT	7
+#define  B43_NPHY_C1_INITGAIN_TRRX		0x1000 /* TR RX index */
+#define  B43_NPHY_C1_INITGAIN_TRTX		0x2000 /* TR TX index */
+#define B43_NPHY_C1_CLIP1_HIGAIN		B43_PHY_N(0x021) /* Core 1 clip1 high gain code */
+#define B43_NPHY_C1_CLIP1_MEDGAIN		B43_PHY_N(0x022) /* Core 1 clip1 medium gain code */
+#define B43_NPHY_C1_CLIP1_LOGAIN		B43_PHY_N(0x023) /* Core 1 clip1 low gain code */
+#define B43_NPHY_C1_CLIP2_GAIN			B43_PHY_N(0x024) /* Core 1 clip2 gain code */
+#define B43_NPHY_C1_FILTERGAIN			B43_PHY_N(0x025) /* Core 1 filter gain */
+#define B43_NPHY_C1_LPF_QHPF_BW			B43_PHY_N(0x026) /* Core 1 LPF Q HP F bandwidth */
+#define B43_NPHY_C1_CLIPWBTHRES			B43_PHY_N(0x027) /* Core 1 clip wideband threshold */
+#define  B43_NPHY_C1_CLIPWBTHRES_CLIP2		0x003F /* Clip 2 */
+#define  B43_NPHY_C1_CLIPWBTHRES_CLIP2_SHIFT	0
+#define  B43_NPHY_C1_CLIPWBTHRES_CLIP1		0x0FC0 /* Clip 1 */
+#define  B43_NPHY_C1_CLIPWBTHRES_CLIP1_SHIFT	6
+#define B43_NPHY_C1_W1THRES			B43_PHY_N(0x028) /* Core 1 W1 threshold */
+#define B43_NPHY_C1_EDTHRES			B43_PHY_N(0x029) /* Core 1 ED threshold */
+#define B43_NPHY_C1_SMSIGTHRES			B43_PHY_N(0x02A) /* Core 1 small sig threshold */
+#define B43_NPHY_C1_NBCLIPTHRES			B43_PHY_N(0x02B) /* Core 1 NB clip threshold */
+#define B43_NPHY_C1_CLIP1THRES			B43_PHY_N(0x02C) /* Core 1 clip1 threshold */
+#define B43_NPHY_C1_CLIP2THRES			B43_PHY_N(0x02D) /* Core 1 clip2 threshold */
+
+#define B43_NPHY_C2_DESPWR			B43_PHY_N(0x02E) /* Core 2 desired power */
+#define B43_NPHY_C2_CCK_DESPWR			B43_PHY_N(0x02F) /* Core 2 CCK desired power */
+#define B43_NPHY_C2_BCLIPBKOFF			B43_PHY_N(0x030) /* Core 2 barely clip backoff */
+#define B43_NPHY_C2_CCK_BCLIPBKOFF		B43_PHY_N(0x031) /* Core 2 CCK barely clip backoff */
+#define B43_NPHY_C2_CGAINI			B43_PHY_N(0x032) /* Core 2 compute gain info */
+#define  B43_NPHY_C2_CGAINI_GAINBKOFF		0x001F /* Gain backoff */
+#define  B43_NPHY_C2_CGAINI_GAINBKOFF_SHIFT	0
+#define  B43_NPHY_C2_CGAINI_CLIPGBKOFF		0x03E0 /* Clip gain backoff */
+#define  B43_NPHY_C2_CGAINI_CLIPGBKOFF_SHIFT	5
+#define  B43_NPHY_C2_CGAINI_GAINSTEP		0x1C00 /* Gain step */
+#define  B43_NPHY_C2_CGAINI_GAINSTEP_SHIFT	10
+#define  B43_NPHY_C2_CGAINI_CL2DETECT		0x2000 /* Clip 2 detect mask */
+#define B43_NPHY_C2_CCK_CGAINI			B43_PHY_N(0x033) /* Core 2 CCK compute gain info */
+#define  B43_NPHY_C2_CCK_CGAINI_GAINBKOFF	0x001F /* Gain backoff */
+#define  B43_NPHY_C2_CCK_CGAINI_CLIPGBKOFF	0x01E0 /* CCK barely clip gain backoff */
+#define B43_NPHY_C2_MINMAX_GAIN			B43_PHY_N(0x034) /* Core 2 min/max gain */
+#define  B43_NPHY_C2_MINGAIN			0x00FF /* Minimum gain */
+#define  B43_NPHY_C2_MINGAIN_SHIFT		0
+#define  B43_NPHY_C2_MAXGAIN			0xFF00 /* Maximum gain */
+#define  B43_NPHY_C2_MAXGAIN_SHIFT		8
+#define B43_NPHY_C2_CCK_MINMAX_GAIN		B43_PHY_N(0x035) /* Core 2 CCK min/max gain */
+#define  B43_NPHY_C2_CCK_MINGAIN		0x00FF /* Minimum gain */
+#define  B43_NPHY_C2_CCK_MINGAIN_SHIFT		0
+#define  B43_NPHY_C2_CCK_MAXGAIN		0xFF00 /* Maximum gain */
+#define  B43_NPHY_C2_CCK_MAXGAIN_SHIFT		8
+#define B43_NPHY_C2_INITGAIN			B43_PHY_N(0x036) /* Core 2 initial gain code */
+#define  B43_NPHY_C2_INITGAIN_EXTLNA		0x0001 /* External LNA index */
+#define  B43_NPHY_C2_INITGAIN_LNA		0x0006 /* LNA index */
+#define  B43_NPHY_C2_INITGAIN_LNAIDX_SHIFT	1
+#define  B43_NPHY_C2_INITGAIN_HPVGA1		0x0078 /* HPVGA1 index */
+#define  B43_NPHY_C2_INITGAIN_HPVGA1_SHIFT	3
+#define  B43_NPHY_C2_INITGAIN_HPVGA2		0x0F80 /* HPVGA2 index */
+#define  B43_NPHY_C2_INITGAIN_HPVGA2_SHIFT	7
+#define  B43_NPHY_C2_INITGAIN_TRRX		0x1000 /* TR RX index */
+#define  B43_NPHY_C2_INITGAIN_TRTX		0x2000 /* TR TX index */
+#define B43_NPHY_C2_CLIP1_HIGAIN		B43_PHY_N(0x037) /* Core 2 clip1 high gain code */
+#define B43_NPHY_C2_CLIP1_MEDGAIN		B43_PHY_N(0x038) /* Core 2 clip1 medium gain code */
+#define B43_NPHY_C2_CLIP1_LOGAIN		B43_PHY_N(0x039) /* Core 2 clip1 low gain code */
+#define B43_NPHY_C2_CLIP2_GAIN			B43_PHY_N(0x03A) /* Core 2 clip2 gain code */
+#define B43_NPHY_C2_FILTERGAIN			B43_PHY_N(0x03B) /* Core 2 filter gain */
+#define B43_NPHY_C2_LPF_QHPF_BW			B43_PHY_N(0x03C) /* Core 2 LPF Q HP F bandwidth */
+#define B43_NPHY_C2_CLIPWBTHRES			B43_PHY_N(0x03D) /* Core 2 clip wideband threshold */
+#define  B43_NPHY_C2_CLIPWBTHRES_CLIP2		0x003F /* Clip 2 */
+#define  B43_NPHY_C2_CLIPWBTHRES_CLIP2_SHIFT	0
+#define  B43_NPHY_C2_CLIPWBTHRES_CLIP1		0x0FC0 /* Clip 1 */
+#define  B43_NPHY_C2_CLIPWBTHRES_CLIP1_SHIFT	6
+#define B43_NPHY_C2_W1THRES			B43_PHY_N(0x03E) /* Core 2 W1 threshold */
+#define B43_NPHY_C2_EDTHRES			B43_PHY_N(0x03F) /* Core 2 ED threshold */
+#define B43_NPHY_C2_SMSIGTHRES			B43_PHY_N(0x040) /* Core 2 small sig threshold */
+#define B43_NPHY_C2_NBCLIPTHRES			B43_PHY_N(0x041) /* Core 2 NB clip threshold */
+#define B43_NPHY_C2_CLIP1THRES			B43_PHY_N(0x042) /* Core 2 clip1 threshold */
+#define B43_NPHY_C2_CLIP2THRES			B43_PHY_N(0x043) /* Core 2 clip2 threshold */
+
+#define B43_NPHY_CRS_THRES1			B43_PHY_N(0x044) /* CRS threshold 1 */
+#define B43_NPHY_CRS_THRES2			B43_PHY_N(0x045) /* CRS threshold 2 */
+#define B43_NPHY_CRS_THRES3			B43_PHY_N(0x046) /* CRS threshold 3 */
+#define B43_NPHY_CRSCTL				B43_PHY_N(0x047) /* CRS control */
+#define B43_NPHY_DCFADDR			B43_PHY_N(0x048) /* DC filter address */
+#define B43_NPHY_RXF20_NUM0			B43_PHY_N(0x049) /* RX filter 20 numerator 0 */
+#define B43_NPHY_RXF20_NUM1			B43_PHY_N(0x04A) /* RX filter 20 numerator 1 */
+#define B43_NPHY_RXF20_NUM2			B43_PHY_N(0x04B) /* RX filter 20 numerator 2 */
+#define B43_NPHY_RXF20_DENOM0			B43_PHY_N(0x04C) /* RX filter 20 denominator 0 */
+#define B43_NPHY_RXF20_DENOM1			B43_PHY_N(0x04D) /* RX filter 20 denominator 1 */
+#define B43_NPHY_RXF20_NUM10			B43_PHY_N(0x04E) /* RX filter 20 numerator 10 */
+#define B43_NPHY_RXF20_NUM11			B43_PHY_N(0x04F) /* RX filter 20 numerator 11 */
+#define B43_NPHY_RXF20_NUM12			B43_PHY_N(0x050) /* RX filter 20 numerator 12 */
+#define B43_NPHY_RXF20_DENOM10			B43_PHY_N(0x051) /* RX filter 20 denominator 10 */
+#define B43_NPHY_RXF20_DENOM11			B43_PHY_N(0x052) /* RX filter 20 denominator 11 */
+#define B43_NPHY_RXF40_NUM0			B43_PHY_N(0x053) /* RX filter 40 numerator 0 */
+#define B43_NPHY_RXF40_NUM1			B43_PHY_N(0x054) /* RX filter 40 numerator 1 */
+#define B43_NPHY_RXF40_NUM2			B43_PHY_N(0x055) /* RX filter 40 numerator 2 */
+#define B43_NPHY_RXF40_DENOM0			B43_PHY_N(0x056) /* RX filter 40 denominator 0 */
+#define B43_NPHY_RXF40_DENOM1			B43_PHY_N(0x057) /* RX filter 40 denominator 1 */
+#define B43_NPHY_RXF40_NUM10			B43_PHY_N(0x058) /* RX filter 40 numerator 10 */
+#define B43_NPHY_RXF40_NUM11			B43_PHY_N(0x059) /* RX filter 40 numerator 11 */
+#define B43_NPHY_RXF40_NUM12			B43_PHY_N(0x05A) /* RX filter 40 numerator 12 */
+#define B43_NPHY_RXF40_DENOM10			B43_PHY_N(0x05B) /* RX filter 40 denominator 10 */
+#define B43_NPHY_RXF40_DENOM11			B43_PHY_N(0x05C) /* RX filter 40 denominator 11 */
+#define B43_NPHY_PPROC_RSTLEN			B43_PHY_N(0x060) /* Packet processing reset length */
+#define B43_NPHY_INITCARR_DLEN			B43_PHY_N(0x061) /* Initial carrier detection length */
+#define B43_NPHY_CLIP1CARR_DLEN			B43_PHY_N(0x062) /* Clip1 carrier detection length */
+#define B43_NPHY_CLIP2CARR_DLEN			B43_PHY_N(0x063) /* Clip2 carrier detection length */
+#define B43_NPHY_INITGAIN_SLEN			B43_PHY_N(0x064) /* Initial gain settle length */
+#define B43_NPHY_CLIP1GAIN_SLEN			B43_PHY_N(0x065) /* Clip1 gain settle length */
+#define B43_NPHY_CLIP2GAIN_SLEN			B43_PHY_N(0x066) /* Clip2 gain settle length */
+#define B43_NPHY_PACKGAIN_SLEN			B43_PHY_N(0x067) /* Packet gain settle length */
+#define B43_NPHY_CARRSRC_TLEN			B43_PHY_N(0x068) /* Carrier search timeout length */
+#define B43_NPHY_TISRC_TLEN			B43_PHY_N(0x069) /* Timing search timeout length */
+#define B43_NPHY_ENDROP_TLEN			B43_PHY_N(0x06A) /* Energy drop timeout length */
+#define B43_NPHY_CLIP1_NBDWELL_LEN		B43_PHY_N(0x06B) /* Clip1 NB dwell length */
+#define B43_NPHY_CLIP2_NBDWELL_LEN		B43_PHY_N(0x06C) /* Clip2 NB dwell length */
+#define B43_NPHY_W1CLIP1_DWELL_LEN		B43_PHY_N(0x06D) /* W1 clip1 dwell length */
+#define B43_NPHY_W1CLIP2_DWELL_LEN		B43_PHY_N(0x06E) /* W1 clip2 dwell length */
+#define B43_NPHY_W2CLIP1_DWELL_LEN		B43_PHY_N(0x06F) /* W2 clip1 dwell length */
+#define B43_NPHY_PLOAD_CSENSE_EXTLEN		B43_PHY_N(0x070) /* Payload carrier sense extension length */
+#define B43_NPHY_EDROP_CSENSE_EXTLEN		B43_PHY_N(0x071) /* Energy drop carrier sense extension length */
+#define B43_NPHY_TABLE_ADDR			B43_PHY_N(0x072) /* Table address */
+#define B43_NPHY_TABLE_DATALO			B43_PHY_N(0x073) /* Table data low */
+#define B43_NPHY_TABLE_DATAHI			B43_PHY_N(0x074) /* Table data high */
+#define B43_NPHY_WWISE_LENIDX			B43_PHY_N(0x075) /* WWiSE length index */
+#define B43_NPHY_TGNSYNC_LENIDX			B43_PHY_N(0x076) /* TGNsync length index */
+#define B43_NPHY_TXMACIF_HOLDOFF		B43_PHY_N(0x077) /* TX MAC IF Hold off */
+#define B43_NPHY_RFCTL_CMD			B43_PHY_N(0x078) /* RF control (command) */
+#define  B43_NPHY_RFCTL_CMD_START		0x0001 /* Start sequence */
+#define  B43_NPHY_RFCTL_CMD_RXTX		0x0002 /* RX/TX */
+#define  B43_NPHY_RFCTL_CMD_CORESEL		0x0038 /* Core select */
+#define  B43_NPHY_RFCTL_CMD_CORESEL_SHIFT	3
+#define  B43_NPHY_RFCTL_CMD_PORFORCE		0x0040 /* POR force */
+#define  B43_NPHY_RFCTL_CMD_OEPORFORCE		0x0080 /* OE POR force */
+#define  B43_NPHY_RFCTL_CMD_RXEN		0x0100 /* RX enable */
+#define  B43_NPHY_RFCTL_CMD_TXEN		0x0200 /* TX enable */
+#define  B43_NPHY_RFCTL_CMD_CHIP0PU		0x0400 /* Chip0 PU */
+#define  B43_NPHY_RFCTL_CMD_EN			0x0800 /* Radio enabled */
+#define  B43_NPHY_RFCTL_CMD_SEQENCORE		0xF000 /* Seq en core */
+#define  B43_NPHY_RFCTL_CMD_SEQENCORE_SHIFT	12
+#define B43_NPHY_RFCTL_RSSIO1			B43_PHY_N(0x07A) /* RF control (RSSI others 1) */
+#define  B43_NPHY_RFCTL_RSSIO1_RXPD		0x0001 /* RX PD */
+#define  B43_NPHY_RFCTL_RSSIO1_TXPD		0x0002 /* TX PD */
+#define  B43_NPHY_RFCTL_RSSIO1_PAPD		0x0004 /* PA PD */
+#define  B43_NPHY_RFCTL_RSSIO1_RSSICTL		0x0030 /* RSSI control */
+#define  B43_NPHY_RFCTL_RSSIO1_LPFBW		0x00C0 /* LPF bandwidth */
+#define  B43_NPHY_RFCTL_RSSIO1_HPFBWHI		0x0100 /* HPF bandwidth high */
+#define  B43_NPHY_RFCTL_RSSIO1_HIQDISCO		0x0200 /* HIQ dis core */
+#define B43_NPHY_RFCTL_RXG1			B43_PHY_N(0x07B) /* RF control (RX gain 1) */
+#define B43_NPHY_RFCTL_TXG1			B43_PHY_N(0x07C) /* RF control (TX gain 1) */
+#define B43_NPHY_RFCTL_RSSIO2			B43_PHY_N(0x07D) /* RF control (RSSI others 2) */
+#define  B43_NPHY_RFCTL_RSSIO2_RXPD		0x0001 /* RX PD */
+#define  B43_NPHY_RFCTL_RSSIO2_TXPD		0x0002 /* TX PD */
+#define  B43_NPHY_RFCTL_RSSIO2_PAPD		0x0004 /* PA PD */
+#define  B43_NPHY_RFCTL_RSSIO2_RSSICTL		0x0030 /* RSSI control */
+#define  B43_NPHY_RFCTL_RSSIO2_LPFBW		0x00C0 /* LPF bandwidth */
+#define  B43_NPHY_RFCTL_RSSIO2_HPFBWHI		0x0100 /* HPF bandwidth high */
+#define  B43_NPHY_RFCTL_RSSIO2_HIQDISCO		0x0200 /* HIQ dis core */
+#define B43_NPHY_RFCTL_RXG2			B43_PHY_N(0x07E) /* RF control (RX gain 2) */
+#define B43_NPHY_RFCTL_TXG2			B43_PHY_N(0x07F) /* RF control (TX gain 2) */
+#define B43_NPHY_RFCTL_RSSIO3			B43_PHY_N(0x080) /* RF control (RSSI others 3) */
+#define  B43_NPHY_RFCTL_RSSIO3_RXPD		0x0001 /* RX PD */
+#define  B43_NPHY_RFCTL_RSSIO3_TXPD		0x0002 /* TX PD */
+#define  B43_NPHY_RFCTL_RSSIO3_PAPD		0x0004 /* PA PD */
+#define  B43_NPHY_RFCTL_RSSIO3_RSSICTL		0x0030 /* RSSI control */
+#define  B43_NPHY_RFCTL_RSSIO3_LPFBW		0x00C0 /* LPF bandwidth */
+#define  B43_NPHY_RFCTL_RSSIO3_HPFBWHI		0x0100 /* HPF bandwidth high */
+#define  B43_NPHY_RFCTL_RSSIO3_HIQDISCO		0x0200 /* HIQ dis core */
+#define B43_NPHY_RFCTL_RXG3			B43_PHY_N(0x081) /* RF control (RX gain 3) */
+#define B43_NPHY_RFCTL_TXG3			B43_PHY_N(0x082) /* RF control (TX gain 3) */
+#define B43_NPHY_RFCTL_RSSIO4			B43_PHY_N(0x083) /* RF control (RSSI others 4) */
+#define  B43_NPHY_RFCTL_RSSIO4_RXPD		0x0001 /* RX PD */
+#define  B43_NPHY_RFCTL_RSSIO4_TXPD		0x0002 /* TX PD */
+#define  B43_NPHY_RFCTL_RSSIO4_PAPD		0x0004 /* PA PD */
+#define  B43_NPHY_RFCTL_RSSIO4_RSSICTL		0x0030 /* RSSI control */
+#define  B43_NPHY_RFCTL_RSSIO4_LPFBW		0x00C0 /* LPF bandwidth */
+#define  B43_NPHY_RFCTL_RSSIO4_HPFBWHI		0x0100 /* HPF bandwidth high */
+#define  B43_NPHY_RFCTL_RSSIO4_HIQDISCO		0x0200 /* HIQ dis core */
+#define B43_NPHY_RFCTL_RXG4			B43_PHY_N(0x084) /* RF control (RX gain 4) */
+#define B43_NPHY_RFCTL_TXG4			B43_PHY_N(0x085) /* RF control (TX gain 4) */
+#define B43_NPHY_C1_TXIQ_COMP_OFF		B43_PHY_N(0x087) /* Core 1 TX I/Q comp offset */
+#define B43_NPHY_C2_TXIQ_COMP_OFF		B43_PHY_N(0x088) /* Core 2 TX I/Q comp offset */
+#define B43_NPHY_C1_TXCTL			B43_PHY_N(0x08B) /* Core 1 TX control */
+#define B43_NPHY_C2_TXCTL			B43_PHY_N(0x08C) /* Core 2 TX control */
+#define B43_NPHY_SCRAM_SIGCTL			B43_PHY_N(0x090) /* Scram signal control */
+#define  B43_NPHY_SCRAM_SIGCTL_INITST		0x007F /* Initial state value */
+#define  B43_NPHY_SCRAM_SIGCTL_INITST_SHIFT	0
+#define  B43_NPHY_SCRAM_SIGCTL_SCM		0x0080 /* Scram control mode */
+#define  B43_NPHY_SCRAM_SIGCTL_SICE		0x0100 /* Scram index control enable */
+#define  B43_NPHY_SCRAM_SIGCTL_START		0xFE00 /* Scram start bit */
+#define  B43_NPHY_SCRAM_SIGCTL_START_SHIFT	9
+#define B43_NPHY_RFCTL_INTC1			B43_PHY_N(0x091) /* RF control (intc 1) */
+#define B43_NPHY_RFCTL_INTC2			B43_PHY_N(0x092) /* RF control (intc 2) */
+#define B43_NPHY_RFCTL_INTC3			B43_PHY_N(0x093) /* RF control (intc 3) */
+#define B43_NPHY_RFCTL_INTC4			B43_PHY_N(0x094) /* RF control (intc 4) */
+#define B43_NPHY_NRDTO_WWISE			B43_PHY_N(0x095) /* # datatones WWiSE */
+#define B43_NPHY_NRDTO_TGNSYNC			B43_PHY_N(0x096) /* # datatones TGNsync */
+#define B43_NPHY_SIGFMOD_WWISE			B43_PHY_N(0x097) /* Signal field mod WWiSE */
+#define B43_NPHY_LEG_SIGFMOD_11N		B43_PHY_N(0x098) /* Legacy signal field mod 11n */
+#define B43_NPHY_HT_SIGFMOD_11N			B43_PHY_N(0x099) /* HT signal field mod 11n */
+#define B43_NPHY_C1_RXIQ_COMPA0			B43_PHY_N(0x09A) /* Core 1 RX I/Q comp A0 */
+#define B43_NPHY_C1_RXIQ_COMPB0			B43_PHY_N(0x09B) /* Core 1 RX I/Q comp B0 */
+#define B43_NPHY_C2_RXIQ_COMPA1			B43_PHY_N(0x09C) /* Core 2 RX I/Q comp A1 */
+#define B43_NPHY_C2_RXIQ_COMPB1			B43_PHY_N(0x09D) /* Core 2 RX I/Q comp B1 */
+#define B43_NPHY_RXCTL				B43_PHY_N(0x0A0) /* RX control */
+#define  B43_NPHY_RXCTL_BSELU20			0x0010 /* Band select upper 20 */
+#define  B43_NPHY_RXCTL_RIFSEN			0x0080 /* RIFS enable */
+#define B43_NPHY_RFSEQMODE			B43_PHY_N(0x0A1) /* RF seq mode */
+#define  B43_NPHY_RFSEQMODE_CAOVER		0x0001 /* Core active override */
+#define  B43_NPHY_RFSEQMODE_TROVER		0x0002 /* Trigger override */
+#define B43_NPHY_RFSEQCA			B43_PHY_N(0x0A2) /* RF seq core active */
+#define  B43_NPHY_RFSEQCA_TXEN			0x000F /* TX enable */
+#define  B43_NPHY_RFSEQCA_TXEN_SHIFT		0
+#define  B43_NPHY_RFSEQCA_RXEN			0x00F0 /* RX enable */
+#define  B43_NPHY_RFSEQCA_RXEN_SHIFT		4
+#define  B43_NPHY_RFSEQCA_TXDIS			0x0F00 /* TX disable */
+#define  B43_NPHY_RFSEQCA_TXDIS_SHIFT		8
+#define  B43_NPHY_RFSEQCA_RXDIS			0xF000 /* RX disable */
+#define  B43_NPHY_RFSEQCA_RXDIS_SHIFT		12
+#define B43_NPHY_RFSEQTR			B43_PHY_N(0x0A3) /* RF seq trigger */
+#define  B43_NPHY_RFSEQTR_RX2TX			0x0001 /* RX2TX */
+#define  B43_NPHY_RFSEQTR_TX2RX			0x0002 /* TX2RX */
+#define  B43_NPHY_RFSEQTR_UPGH			0x0004 /* Update gain H */
+#define  B43_NPHY_RFSEQTR_UPGL			0x0008 /* Update gain L */
+#define  B43_NPHY_RFSEQTR_UPGU			0x0010 /* Update gain U */
+#define  B43_NPHY_RFSEQTR_RST2RX		0x0020 /* Reset to RX */
+#define B43_NPHY_RFSEQST			B43_PHY_N(0x0A4) /* RF seq status. Values same as trigger. */
+#define B43_NPHY_AFECTL_OVER			B43_PHY_N(0x0A5) /* AFE control override */
+#define B43_NPHY_AFECTL_C1			B43_PHY_N(0x0A6) /* AFE control core 1 */
+#define B43_NPHY_AFECTL_C2			B43_PHY_N(0x0A7) /* AFE control core 2 */
+#define B43_NPHY_AFECTL_C3			B43_PHY_N(0x0A8) /* AFE control core 3 */
+#define B43_NPHY_AFECTL_C4			B43_PHY_N(0x0A9) /* AFE control core 4 */
+#define B43_NPHY_AFECTL_DACGAIN1		B43_PHY_N(0x0AA) /* AFE control DAC gain 1 */
+#define B43_NPHY_AFECTL_DACGAIN2		B43_PHY_N(0x0AB) /* AFE control DAC gain 2 */
+#define B43_NPHY_AFECTL_DACGAIN3		B43_PHY_N(0x0AC) /* AFE control DAC gain 3 */
+#define B43_NPHY_AFECTL_DACGAIN4		B43_PHY_N(0x0AD) /* AFE control DAC gain 4 */
+#define B43_NPHY_STR_ADDR1			B43_PHY_N(0x0AE) /* STR address 1 */
+#define B43_NPHY_STR_ADDR2			B43_PHY_N(0x0AF) /* STR address 2 */
+#define B43_NPHY_CLASSCTL			B43_PHY_N(0x0B0) /* Classifier control */
+#define  B43_NPHY_CLASSCTL_CCKEN		0x0001 /* CCK enable */
+#define  B43_NPHY_CLASSCTL_OFDMEN		0x0002 /* OFDM enable */
+#define  B43_NPHY_CLASSCTL_WAITEDEN		0x0004 /* Waited enable */
+#define B43_NPHY_IQFLIP				B43_PHY_N(0x0B1) /* I/Q flip */
+#define  B43_NPHY_IQFLIP_ADC1			0x0001 /* ADC1 */
+#define  B43_NPHY_IQFLIP_ADC2			0x0010 /* ADC2 */
+#define B43_NPHY_SISO_SNR_THRES			B43_PHY_N(0x0B2) /* SISO SNR threshold */
+#define B43_NPHY_SIGMA_N_MULT			B43_PHY_N(0x0B3) /* Sigma N multiplier */
+#define B43_NPHY_TXMACDELAY			B43_PHY_N(0x0B4) /* TX MAC delay */
+#define B43_NPHY_TXFRAMEDELAY			B43_PHY_N(0x0B5) /* TX frame delay */
+#define B43_NPHY_MLPARM				B43_PHY_N(0x0B6) /* ML parameters */
+#define B43_NPHY_MLCTL				B43_PHY_N(0x0B7) /* ML control */
+#define B43_NPHY_WWISE_20NCYCDAT		B43_PHY_N(0x0B8) /* WWiSE 20 N cyc data */
+#define B43_NPHY_WWISE_40NCYCDAT		B43_PHY_N(0x0B9) /* WWiSE 40 N cyc data */
+#define B43_NPHY_TGNSYNC_20NCYCDAT		B43_PHY_N(0x0BA) /* TGNsync 20 N cyc data */
+#define B43_NPHY_TGNSYNC_40NCYCDAT		B43_PHY_N(0x0BB) /* TGNsync 40 N cyc data */
+#define B43_NPHY_INITSWIZP			B43_PHY_N(0x0BC) /* Initial swizzle pattern */
+#define B43_NPHY_TXTAILCNT			B43_PHY_N(0x0BD) /* TX tail count value */
+#define B43_NPHY_BPHY_CTL1			B43_PHY_N(0x0BE) /* B PHY control 1 */
+#define B43_NPHY_BPHY_CTL2			B43_PHY_N(0x0BF) /* B PHY control 2 */
+#define  B43_NPHY_BPHY_CTL2_LUT			0x001F /* LUT index */
+#define  B43_NPHY_BPHY_CTL2_LUT_SHIFT		0
+#define  B43_NPHY_BPHY_CTL2_MACDEL		0x7FE0 /* MAC delay */
+#define  B43_NPHY_BPHY_CTL2_MACDEL_SHIFT	5
+#define B43_NPHY_IQLOCAL_CMD			B43_PHY_N(0x0C0) /* I/Q LO cal command */
+#define  B43_NPHY_IQLOCAL_CMD_EN		0x8000
+#define B43_NPHY_IQLOCAL_CMDNNUM		B43_PHY_N(0x0C1) /* I/Q LO cal command N num */
+#define B43_NPHY_IQLOCAL_CMDGCTL		B43_PHY_N(0x0C2) /* I/Q LO cal command G control */
+#define B43_NPHY_SAMP_CMD			B43_PHY_N(0x0C3) /* Sample command */
+#define  B43_NPHY_SAMP_CMD_STOP			0x0002 /* Stop */
+#define B43_NPHY_SAMP_LOOPCNT			B43_PHY_N(0x0C4) /* Sample loop count */
+#define B43_NPHY_SAMP_WAITCNT			B43_PHY_N(0x0C5) /* Sample wait count */
+#define B43_NPHY_SAMP_DEPCNT			B43_PHY_N(0x0C6) /* Sample depth count */
+#define B43_NPHY_SAMP_STAT			B43_PHY_N(0x0C7) /* Sample status */
+#define B43_NPHY_GPIO_LOOEN			B43_PHY_N(0x0C8) /* GPIO low out enable */
+#define B43_NPHY_GPIO_HIOEN			B43_PHY_N(0x0C9) /* GPIO high out enable */
+#define B43_NPHY_GPIO_SEL			B43_PHY_N(0x0CA) /* GPIO select */
+#define B43_NPHY_GPIO_CLKCTL			B43_PHY_N(0x0CB) /* GPIO clock control */
+#define B43_NPHY_TXF_20CO_AS0			B43_PHY_N(0x0CC) /* TX filter 20 coeff A stage 0 */
+#define B43_NPHY_TXF_20CO_AS1			B43_PHY_N(0x0CD) /* TX filter 20 coeff A stage 1 */
+#define B43_NPHY_TXF_20CO_AS2			B43_PHY_N(0x0CE) /* TX filter 20 coeff A stage 2 */
+#define B43_NPHY_TXF_20CO_B32S0			B43_PHY_N(0x0CF) /* TX filter 20 coeff B32 stage 0 */
+#define B43_NPHY_TXF_20CO_B1S0			B43_PHY_N(0x0D0) /* TX filter 20 coeff B1 stage 0 */
+#define B43_NPHY_TXF_20CO_B32S1			B43_PHY_N(0x0D1) /* TX filter 20 coeff B32 stage 1 */
+#define B43_NPHY_TXF_20CO_B1S1			B43_PHY_N(0x0D2) /* TX filter 20 coeff B1 stage 1 */
+#define B43_NPHY_TXF_20CO_B32S2			B43_PHY_N(0x0D3) /* TX filter 20 coeff B32 stage 2 */
+#define B43_NPHY_TXF_20CO_B1S2			B43_PHY_N(0x0D4) /* TX filter 20 coeff B1 stage 2 */
+#define B43_NPHY_SIGFLDTOL			B43_PHY_N(0x0D5) /* Signal fld tolerance */
+#define B43_NPHY_TXSERFLD			B43_PHY_N(0x0D6) /* TX service field */
+#define B43_NPHY_AFESEQ_RX2TX_PUD		B43_PHY_N(0x0D7) /* AFE seq RX2TX power up/down delay */
+#define B43_NPHY_AFESEQ_TX2RX_PUD		B43_PHY_N(0x0D8) /* AFE seq TX2RX power up/down delay */
+#define B43_NPHY_TGNSYNC_SCRAMI0		B43_PHY_N(0x0D9) /* TGNsync scram init 0 */
+#define B43_NPHY_TGNSYNC_SCRAMI1		B43_PHY_N(0x0DA) /* TGNsync scram init 1 */
+#define B43_NPHY_INITSWIZPATTLEG		B43_PHY_N(0x0DB) /* Initial swizzle pattern leg */
+#define B43_NPHY_BPHY_CTL3			B43_PHY_N(0x0DC) /* B PHY control 3 */
+#define  B43_NPHY_BPHY_CTL3_SCALE		0x00FF /* Scale */
+#define  B43_NPHY_BPHY_CTL3_SCALE_SHIFT		0
+#define  B43_NPHY_BPHY_CTL3_FSC			0xFF00 /* Frame start count value */
+#define  B43_NPHY_BPHY_CTL3_FSC_SHIFT		8
+#define B43_NPHY_BPHY_CTL4			B43_PHY_N(0x0DD) /* B PHY control 4 */
+#define B43_NPHY_C1_TXBBMULT			B43_PHY_N(0x0DE) /* Core 1 TX BB multiplier */
+#define B43_NPHY_C2_TXBBMULT			B43_PHY_N(0x0DF) /* Core 2 TX BB multiplier */
+#define B43_NPHY_TXF_40CO_AS0			B43_PHY_N(0x0E1) /* TX filter 40 coeff A stage 0 */
+#define B43_NPHY_TXF_40CO_AS1			B43_PHY_N(0x0E2) /* TX filter 40 coeff A stage 1 */
+#define B43_NPHY_TXF_40CO_AS2			B43_PHY_N(0x0E3) /* TX filter 40 coeff A stage 2 */
+#define B43_NPHY_TXF_40CO_B32S0			B43_PHY_N(0x0E4) /* TX filter 40 coeff B32 stage 0 */
+#define B43_NPHY_TXF_40CO_B1S0			B43_PHY_N(0x0E5) /* TX filter 40 coeff B1 stage 0 */
+#define B43_NPHY_TXF_40CO_B32S1			B43_PHY_N(0x0E6) /* TX filter 40 coeff B32 stage 1 */
+#define B43_NPHY_TXF_40CO_B1S1			B43_PHY_N(0x0E7) /* TX filter 40 coeff B1 stage 1 */
+#define B43_NPHY_TXF_40CO_B32S2			B43_PHY_N(0x0E8) /* TX filter 40 coeff B32 stage 2 */
+#define B43_NPHY_TXF_40CO_B1S2			B43_PHY_N(0x0E9) /* TX filter 40 coeff B1 stage 2 */
+#define B43_NPHY_BIST_STAT2			B43_PHY_N(0x0EA) /* BIST status 2 */
+#define B43_NPHY_BIST_STAT3			B43_PHY_N(0x0EB) /* BIST status 3 */
+#define B43_NPHY_RFCTL_OVER			B43_PHY_N(0x0EC) /* RF control override */
+#define B43_NPHY_MIMOCFG			B43_PHY_N(0x0ED) /* MIMO config */
+#define  B43_NPHY_MIMOCFG_GFMIX			0x0004 /* Greenfield or mixed mode */
+#define  B43_NPHY_MIMOCFG_AUTO			0x0100 /* Greenfield/mixed mode auto */
+#define B43_NPHY_RADAR_BLNKCTL			B43_PHY_N(0x0EE) /* Radar blank control */
+#define B43_NPHY_A0RADAR_FIFOCTL		B43_PHY_N(0x0EF) /* Antenna 0 radar FIFO control */
+#define B43_NPHY_A1RADAR_FIFOCTL		B43_PHY_N(0x0F0) /* Antenna 1 radar FIFO control */
+#define B43_NPHY_A0RADAR_FIFODAT		B43_PHY_N(0x0F1) /* Antenna 0 radar FIFO data */
+#define B43_NPHY_A1RADAR_FIFODAT		B43_PHY_N(0x0F2) /* Antenna 1 radar FIFO data */
+#define B43_NPHY_RADAR_THRES0			B43_PHY_N(0x0F3) /* Radar threshold 0 */
+#define B43_NPHY_RADAR_THRES1			B43_PHY_N(0x0F4) /* Radar threshold 1 */
+#define B43_NPHY_RADAR_THRES0R			B43_PHY_N(0x0F5) /* Radar threshold 0R */
+#define B43_NPHY_RADAR_THRES1R			B43_PHY_N(0x0F6) /* Radar threshold 1R */
+#define B43_NPHY_CSEN_20IN40_DLEN		B43_PHY_N(0x0F7) /* Carrier sense 20 in 40 dwell length */
+#define B43_NPHY_RFCTL_LUT_TRSW_LO1		B43_PHY_N(0x0F8) /* RF control LUT TRSW lower 1 */
+#define B43_NPHY_RFCTL_LUT_TRSW_UP1		B43_PHY_N(0x0F9) /* RF control LUT TRSW upper 1 */
+#define B43_NPHY_RFCTL_LUT_TRSW_LO2		B43_PHY_N(0x0FA) /* RF control LUT TRSW lower 2 */
+#define B43_NPHY_RFCTL_LUT_TRSW_UP2		B43_PHY_N(0x0FB) /* RF control LUT TRSW upper 2 */
+#define B43_NPHY_RFCTL_LUT_TRSW_LO3		B43_PHY_N(0x0FC) /* RF control LUT TRSW lower 3 */
+#define B43_NPHY_RFCTL_LUT_TRSW_UP3		B43_PHY_N(0x0FD) /* RF control LUT TRSW upper 3 */
+#define B43_NPHY_RFCTL_LUT_TRSW_LO4		B43_PHY_N(0x0FE) /* RF control LUT TRSW lower 4 */
+#define B43_NPHY_RFCTL_LUT_TRSW_UP4		B43_PHY_N(0x0FF) /* RF control LUT TRSW upper 4 */
+#define B43_NPHY_RFCTL_LUT_LNAPA1		B43_PHY_N(0x100) /* RF control LUT LNA PA 1 */
+#define B43_NPHY_RFCTL_LUT_LNAPA2		B43_PHY_N(0x101) /* RF control LUT LNA PA 2 */
+#define B43_NPHY_RFCTL_LUT_LNAPA3		B43_PHY_N(0x102) /* RF control LUT LNA PA 3 */
+#define B43_NPHY_RFCTL_LUT_LNAPA4		B43_PHY_N(0x103) /* RF control LUT LNA PA 4 */
+#define B43_NPHY_TGNSYNC_CRCM0			B43_PHY_N(0x104) /* TGNsync CRC mask 0 */
+#define B43_NPHY_TGNSYNC_CRCM1			B43_PHY_N(0x105) /* TGNsync CRC mask 1 */
+#define B43_NPHY_TGNSYNC_CRCM2			B43_PHY_N(0x106) /* TGNsync CRC mask 2 */
+#define B43_NPHY_TGNSYNC_CRCM3			B43_PHY_N(0x107) /* TGNsync CRC mask 3 */
+#define B43_NPHY_TGNSYNC_CRCM4			B43_PHY_N(0x108) /* TGNsync CRC mask 4 */
+#define B43_NPHY_CRCPOLY			B43_PHY_N(0x109) /* CRC polynomial */
+#define B43_NPHY_SIGCNT				B43_PHY_N(0x10A) /* # sig count */
+#define B43_NPHY_SIGSTARTBIT_CTL		B43_PHY_N(0x10B) /* Sig start bit control */
+#define B43_NPHY_CRCPOLY_ORDER			B43_PHY_N(0x10C) /* CRC polynomial order */
+#define B43_NPHY_RFCTL_CST0			B43_PHY_N(0x10D) /* RF control core swap table 0 */
+#define B43_NPHY_RFCTL_CST1			B43_PHY_N(0x10E) /* RF control core swap table 1 */
+#define B43_NPHY_RFCTL_CST2O			B43_PHY_N(0x10F) /* RF control core swap table 2 + others */
+#define B43_NPHY_BPHY_CTL5			B43_PHY_N(0x111) /* B PHY control 5 */
+#define B43_NPHY_RFSEQ_LPFBW			B43_PHY_N(0x112) /* RF seq LPF bandwidth */
+#define B43_NPHY_TSSIBIAS1			B43_PHY_N(0x114) /* TSSI bias val 1 */
+#define B43_NPHY_TSSIBIAS2			B43_PHY_N(0x115) /* TSSI bias val 2 */
+#define  B43_NPHY_TSSIBIAS_BIAS			0x00FF /* Bias */
+#define  B43_NPHY_TSSIBIAS_BIAS_SHIFT		0
+#define  B43_NPHY_TSSIBIAS_VAL			0xFF00 /* Value */
+#define  B43_NPHY_TSSIBIAS_VAL_SHIFT		8
+#define B43_NPHY_ESTPWR1			B43_PHY_N(0x118) /* Estimated power 1 */
+#define B43_NPHY_ESTPWR2			B43_PHY_N(0x119) /* Estimated power 2 */
+#define  B43_NPHY_ESTPWR_PWR			0x00FF /* Estimated power */
+#define  B43_NPHY_ESTPWR_PWR_SHIFT		0
+#define  B43_NPHY_ESTPWR_VALID			0x0100 /* Estimated power valid */
+#define B43_NPHY_TSSI_MAXTXFDT			B43_PHY_N(0x11C) /* TSSI max TX frame delay time */
+#define  B43_NPHY_TSSI_MAXTXFDT_VAL		0x00FF /* max TX frame delay time */
+#define  B43_NPHY_TSSI_MAXTXFDT_VAL_SHIFT	0
+#define B43_NPHY_TSSI_MAXTDT			B43_PHY_N(0x11D) /* TSSI max TSSI delay time */
+#define  B43_NPHY_TSSI_MAXTDT_VAL		0x00FF /* max TSSI delay time */
+#define  B43_NPHY_TSSI_MAXTDT_VAL_SHIFT		0
+#define B43_NPHY_ITSSI1				B43_PHY_N(0x11E) /* TSSI idle 1 */
+#define B43_NPHY_ITSSI2				B43_PHY_N(0x11F) /* TSSI idle 2 */
+#define  B43_NPHY_ITSSI_VAL			0x00FF /* Idle TSSI */
+#define  B43_NPHY_ITSSI_VAL_SHIFT		0
+#define B43_NPHY_TSSIMODE			B43_PHY_N(0x122) /* TSSI mode */
+#define  B43_NPHY_TSSIMODE_EN			0x0001 /* TSSI enable */
+#define  B43_NPHY_TSSIMODE_PDEN			0x0002 /* Power det enable */
+#define B43_NPHY_RXMACIFM			B43_PHY_N(0x123) /* RX Macif mode */
+#define B43_NPHY_CRSIT_COCNT_LO			B43_PHY_N(0x124) /* CRS idle time CRS-on count (low) */
+#define B43_NPHY_CRSIT_COCNT_HI			B43_PHY_N(0x125) /* CRS idle time CRS-on count (high) */
+#define B43_NPHY_CRSIT_MTCNT_LO			B43_PHY_N(0x126) /* CRS idle time measure time count (low) */
+#define B43_NPHY_CRSIT_MTCNT_HI			B43_PHY_N(0x127) /* CRS idle time measure time count (high) */
+#define B43_NPHY_SAMTWC				B43_PHY_N(0x128) /* Sample tail wait count */
+#define B43_NPHY_IQEST_CMD			B43_PHY_N(0x129) /* I/Q estimate command */
+#define  B43_NPHY_IQEST_CMD_START		0x0001 /* Start */
+#define  B43_NPHY_IQEST_CMD_MODE		0x0002 /* Mode */
+#define B43_NPHY_IQEST_WT			B43_PHY_N(0x12A) /* I/Q estimate wait time */
+#define  B43_NPHY_IQEST_WT_VAL			0x00FF /* Wait time */
+#define  B43_NPHY_IQEST_WT_VAL_SHIFT		0
+#define B43_NPHY_IQEST_SAMCNT			B43_PHY_N(0x12B) /* I/Q estimate sample count */
+#define B43_NPHY_IQEST_IQACC_LO0		B43_PHY_N(0x12C) /* I/Q estimate I/Q acc lo 0 */
+#define B43_NPHY_IQEST_IQACC_HI0		B43_PHY_N(0x12D) /* I/Q estimate I/Q acc hi 0 */
+#define B43_NPHY_IQEST_IPACC_LO0		B43_PHY_N(0x12E) /* I/Q estimate I power acc lo 0 */
+#define B43_NPHY_IQEST_IPACC_HI0		B43_PHY_N(0x12F) /* I/Q estimate I power acc hi 0 */
+#define B43_NPHY_IQEST_QPACC_LO0		B43_PHY_N(0x130) /* I/Q estimate Q power acc lo 0 */
+#define B43_NPHY_IQEST_QPACC_HI0		B43_PHY_N(0x131) /* I/Q estimate Q power acc hi 0 */
+#define B43_NPHY_IQEST_IQACC_LO1		B43_PHY_N(0x134) /* I/Q estimate I/Q acc lo 1 */
+#define B43_NPHY_IQEST_IQACC_HI1		B43_PHY_N(0x135) /* I/Q estimate I/Q acc hi 1 */
+#define B43_NPHY_IQEST_IPACC_LO1		B43_PHY_N(0x136) /* I/Q estimate I power acc lo 1 */
+#define B43_NPHY_IQEST_IPACC_HI1		B43_PHY_N(0x137) /* I/Q estimate I power acc hi 1 */
+#define B43_NPHY_IQEST_QPACC_LO1		B43_PHY_N(0x138) /* I/Q estimate Q power acc lo 1 */
+#define B43_NPHY_IQEST_QPACC_HI1		B43_PHY_N(0x139) /* I/Q estimate Q power acc hi 1 */
+#define B43_NPHY_MIMO_CRSTXEXT			B43_PHY_N(0x13A) /* MIMO PHY CRS TX extension */
+#define B43_NPHY_PWRDET1			B43_PHY_N(0x13B) /* Power det 1 */
+#define B43_NPHY_PWRDET2			B43_PHY_N(0x13C) /* Power det 2 */
+#define B43_NPHY_MAXRSSI_DTIME			B43_PHY_N(0x13F) /* RSSI max RSSI delay time */
+#define B43_NPHY_PIL_DW0			B43_PHY_N(0x141) /* Pilot data weight 0 */
+#define B43_NPHY_PIL_DW1			B43_PHY_N(0x142) /* Pilot data weight 1 */
+#define B43_NPHY_PIL_DW2			B43_PHY_N(0x143) /* Pilot data weight 2 */
+#define  B43_NPHY_PIL_DW_BPSK			0x000F /* BPSK */
+#define  B43_NPHY_PIL_DW_BPSK_SHIFT		0
+#define  B43_NPHY_PIL_DW_QPSK			0x00F0 /* QPSK */
+#define  B43_NPHY_PIL_DW_QPSK_SHIFT		4
+#define  B43_NPHY_PIL_DW_16QAM			0x0F00 /* 16-QAM */
+#define  B43_NPHY_PIL_DW_16QAM_SHIFT		8
+#define  B43_NPHY_PIL_DW_64QAM			0xF000 /* 64-QAM */
+#define  B43_NPHY_PIL_DW_64QAM_SHIFT		12
+#define B43_NPHY_FMDEM_CFG			B43_PHY_N(0x144) /* FM demodulation config */
+#define B43_NPHY_PHASETR_A0			B43_PHY_N(0x145) /* Phase track alpha 0 */
+#define B43_NPHY_PHASETR_A1			B43_PHY_N(0x146) /* Phase track alpha 1 */
+#define B43_NPHY_PHASETR_A2			B43_PHY_N(0x147) /* Phase track alpha 2 */
+#define B43_NPHY_PHASETR_B0			B43_PHY_N(0x148) /* Phase track beta 0 */
+#define B43_NPHY_PHASETR_B1			B43_PHY_N(0x149) /* Phase track beta 1 */
+#define B43_NPHY_PHASETR_B2			B43_PHY_N(0x14A) /* Phase track beta 2 */
+#define B43_NPHY_PHASETR_CHG0			B43_PHY_N(0x14B) /* Phase track change 0 */
+#define B43_NPHY_PHASETR_CHG1			B43_PHY_N(0x14C) /* Phase track change 1 */
+#define B43_NPHY_PHASETW_OFF			B43_PHY_N(0x14D) /* Phase track offset */
+#define B43_NPHY_RFCTL_DBG			B43_PHY_N(0x14E) /* RF control debug */
+#define B43_NPHY_CCK_SHIFTB_REF			B43_PHY_N(0x150) /* CCK shiftbits reference var */
+#define B43_NPHY_OVER_DGAIN0			B43_PHY_N(0x152) /* Override digital gain 0 */
+#define B43_NPHY_OVER_DGAIN1			B43_PHY_N(0x153) /* Override digital gain 1 */
+#define  B43_NPHY_OVER_DGAIN_FDGV		0x0007 /* Force digital gain value */
+#define  B43_NPHY_OVER_DGAIN_FDGV_SHIFT		0
+#define  B43_NPHY_OVER_DGAIN_FDGEN		0x0008 /* Force digital gain enable */
+#define  B43_NPHY_OVER_DGAIN_CCKDGECV		0xFF00 /* CCK digital gain enable count value */
+#define  B43_NPHY_OVER_DGAIN_CCKDGECV_SHIFT	8
+#define B43_NPHY_BIST_STAT4			B43_PHY_N(0x156) /* BIST status 4 */
+#define B43_NPHY_RADAR_MAL			B43_PHY_N(0x157) /* Radar MA length */
+#define B43_NPHY_RADAR_SRCCTL			B43_PHY_N(0x158) /* Radar search control */
+#define B43_NPHY_VLD_DTSIG			B43_PHY_N(0x159) /* VLD data tones sig */
+#define B43_NPHY_VLD_DTDAT			B43_PHY_N(0x15A) /* VLD data tones data */
+#define B43_NPHY_C1_BPHY_RXIQCA0		B43_PHY_N(0x15B) /* Core 1 B PHY RX I/Q comp A0 */
+#define B43_NPHY_C1_BPHY_RXIQCB0		B43_PHY_N(0x15C) /* Core 1 B PHY RX I/Q comp B0 */
+#define B43_NPHY_C2_BPHY_RXIQCA1		B43_PHY_N(0x15D) /* Core 2 B PHY RX I/Q comp A1 */
+#define B43_NPHY_C2_BPHY_RXIQCB1		B43_PHY_N(0x15E) /* Core 2 B PHY RX I/Q comp B1 */
+#define B43_NPHY_FREQGAIN0			B43_PHY_N(0x160) /* Frequency gain 0 */
+#define B43_NPHY_FREQGAIN1			B43_PHY_N(0x161) /* Frequency gain 1 */
+#define B43_NPHY_FREQGAIN2			B43_PHY_N(0x162) /* Frequency gain 2 */
+#define B43_NPHY_FREQGAIN3			B43_PHY_N(0x163) /* Frequency gain 3 */
+#define B43_NPHY_FREQGAIN4			B43_PHY_N(0x164) /* Frequency gain 4 */
+#define B43_NPHY_FREQGAIN5			B43_PHY_N(0x165) /* Frequency gain 5 */
+#define B43_NPHY_FREQGAIN6			B43_PHY_N(0x166) /* Frequency gain 6 */
+#define B43_NPHY_FREQGAIN7			B43_PHY_N(0x167) /* Frequency gain 7 */
+#define B43_NPHY_FREQGAIN_BYPASS		B43_PHY_N(0x168) /* Frequency gain bypass */
+#define B43_NPHY_TRLOSS				B43_PHY_N(0x169) /* TR loss value */
+#define B43_NPHY_C1_ADCCLIP			B43_PHY_N(0x16A) /* Core 1 ADC clip */
+#define B43_NPHY_C2_ADCCLIP			B43_PHY_N(0x16B) /* Core 2 ADC clip */
+#define B43_NPHY_LTRN_OFFGAIN			B43_PHY_N(0x16F) /* LTRN offset gain */
+#define B43_NPHY_LTRN_OFF			B43_PHY_N(0x170) /* LTRN offset */
+#define B43_NPHY_NRDATAT_WWISE20SIG		B43_PHY_N(0x171) /* # data tones WWiSE 20 sig */
+#define B43_NPHY_NRDATAT_WWISE40SIG		B43_PHY_N(0x172) /* # data tones WWiSE 40 sig */
+#define B43_NPHY_NRDATAT_TGNSYNC20SIG		B43_PHY_N(0x173) /* # data tones TGNsync 20 sig */
+#define B43_NPHY_NRDATAT_TGNSYNC40SIG		B43_PHY_N(0x174) /* # data tones TGNsync 40 sig */
+#define B43_NPHY_WWISE_CRCM0			B43_PHY_N(0x175) /* WWiSE CRC mask 0 */
+#define B43_NPHY_WWISE_CRCM1			B43_PHY_N(0x176) /* WWiSE CRC mask 1 */
+#define B43_NPHY_WWISE_CRCM2			B43_PHY_N(0x177) /* WWiSE CRC mask 2 */
+#define B43_NPHY_WWISE_CRCM3			B43_PHY_N(0x178) /* WWiSE CRC mask 3 */
+#define B43_NPHY_WWISE_CRCM4			B43_PHY_N(0x179) /* WWiSE CRC mask 4 */
+#define B43_NPHY_CHANEST_CDDSH			B43_PHY_N(0x17A) /* Channel estimate CDD shift */
+#define B43_NPHY_HTAGC_WCNT			B43_PHY_N(0x17B) /* HT ADC wait counters */
+#define B43_NPHY_SQPARM				B43_PHY_N(0x17C) /* SQ params */
+#define B43_NPHY_MCSDUP6M			B43_PHY_N(0x17D) /* MCS dup 6M */
+#define B43_NPHY_NDATAT_DUP40			B43_PHY_N(0x17E) /* # data tones dup 40 */
+#define B43_NPHY_DUP40_TGNSYNC_CYCD		B43_PHY_N(0x17F) /* Dup40 TGNsync cycle data */
+#define B43_NPHY_DUP40_GFBL			B43_PHY_N(0x180) /* Dup40 GF format BL address */
+#define B43_NPHY_DUP40_BL			B43_PHY_N(0x181) /* Dup40 format BL address */
+#define B43_NPHY_LEGDUP_FTA			B43_PHY_N(0x182) /* Legacy dup frm table address */
+#define B43_NPHY_PACPROC_DBG			B43_PHY_N(0x183) /* Packet processing debug */
+#define B43_NPHY_PIL_CYC1			B43_PHY_N(0x184) /* Pilot cycle counter 1 */
+#define B43_NPHY_PIL_CYC2			B43_PHY_N(0x185) /* Pilot cycle counter 2 */
+#define B43_NPHY_TXF_20CO_S0A1			B43_PHY_N(0x186) /* TX filter 20 coeff stage 0 A1 */
+#define B43_NPHY_TXF_20CO_S0A2			B43_PHY_N(0x187) /* TX filter 20 coeff stage 0 A2 */
+#define B43_NPHY_TXF_20CO_S1A1			B43_PHY_N(0x188) /* TX filter 20 coeff stage 1 A1 */
+#define B43_NPHY_TXF_20CO_S1A2			B43_PHY_N(0x189) /* TX filter 20 coeff stage 1 A2 */
+#define B43_NPHY_TXF_20CO_S2A1			B43_PHY_N(0x18A) /* TX filter 20 coeff stage 2 A1 */
+#define B43_NPHY_TXF_20CO_S2A2			B43_PHY_N(0x18B) /* TX filter 20 coeff stage 2 A2 */
+#define B43_NPHY_TXF_20CO_S0B1			B43_PHY_N(0x18C) /* TX filter 20 coeff stage 0 B1 */
+#define B43_NPHY_TXF_20CO_S0B2			B43_PHY_N(0x18D) /* TX filter 20 coeff stage 0 B2 */
+#define B43_NPHY_TXF_20CO_S0B3			B43_PHY_N(0x18E) /* TX filter 20 coeff stage 0 B3 */
+#define B43_NPHY_TXF_20CO_S1B1			B43_PHY_N(0x18F) /* TX filter 20 coeff stage 1 B1 */
+#define B43_NPHY_TXF_20CO_S1B2			B43_PHY_N(0x190) /* TX filter 20 coeff stage 1 B2 */
+#define B43_NPHY_TXF_20CO_S1B3			B43_PHY_N(0x191) /* TX filter 20 coeff stage 1 B3 */
+#define B43_NPHY_TXF_20CO_S2B1			B43_PHY_N(0x192) /* TX filter 20 coeff stage 2 B1 */
+#define B43_NPHY_TXF_20CO_S2B2			B43_PHY_N(0x193) /* TX filter 20 coeff stage 2 B2 */
+#define B43_NPHY_TXF_20CO_S2B3			B43_PHY_N(0x194) /* TX filter 20 coeff stage 2 B3 */
+#define B43_NPHY_TXF_40CO_S0A1			B43_PHY_N(0x195) /* TX filter 40 coeff stage 0 A1 */
+#define B43_NPHY_TXF_40CO_S0A2			B43_PHY_N(0x196) /* TX filter 40 coeff stage 0 A2 */
+#define B43_NPHY_TXF_40CO_S1A1			B43_PHY_N(0x197) /* TX filter 40 coeff stage 1 A1 */
+#define B43_NPHY_TXF_40CO_S1A2			B43_PHY_N(0x198) /* TX filter 40 coeff stage 1 A2 */
+#define B43_NPHY_TXF_40CO_S2A1			B43_PHY_N(0x199) /* TX filter 40 coeff stage 2 A1 */
+#define B43_NPHY_TXF_40CO_S2A2			B43_PHY_N(0x19A) /* TX filter 40 coeff stage 2 A2 */
+#define B43_NPHY_TXF_40CO_S0B1			B43_PHY_N(0x19B) /* TX filter 40 coeff stage 0 B1 */
+#define B43_NPHY_TXF_40CO_S0B2			B43_PHY_N(0x19C) /* TX filter 40 coeff stage 0 B2 */
+#define B43_NPHY_TXF_40CO_S0B3			B43_PHY_N(0x19D) /* TX filter 40 coeff stage 0 B3 */
+#define B43_NPHY_TXF_40CO_S1B1			B43_PHY_N(0x19E) /* TX filter 40 coeff stage 1 B1 */
+#define B43_NPHY_TXF_40CO_S1B2			B43_PHY_N(0x19F) /* TX filter 40 coeff stage 1 B2 */
+#define B43_NPHY_TXF_40CO_S1B3			B43_PHY_N(0x1A0) /* TX filter 40 coeff stage 1 B3 */
+#define B43_NPHY_TXF_40CO_S2B1			B43_PHY_N(0x1A1) /* TX filter 40 coeff stage 2 B1 */
+#define B43_NPHY_TXF_40CO_S2B2			B43_PHY_N(0x1A2) /* TX filter 40 coeff stage 2 B2 */
+#define B43_NPHY_TXF_40CO_S2B3			B43_PHY_N(0x1A3) /* TX filter 40 coeff stage 2 B3 */
+#define B43_NPHY_RSSIMC_0I_RSSI_X		B43_PHY_N(0x1A4) /* RSSI multiplication coefficient 0 I RSSI X */
+#define B43_NPHY_RSSIMC_0I_RSSI_Y		B43_PHY_N(0x1A5) /* RSSI multiplication coefficient 0 I RSSI Y */
+#define B43_NPHY_RSSIMC_0I_RSSI_Z		B43_PHY_N(0x1A6) /* RSSI multiplication coefficient 0 I RSSI Z */
+#define B43_NPHY_RSSIMC_0I_TBD			B43_PHY_N(0x1A7) /* RSSI multiplication coefficient 0 I TBD */
+#define B43_NPHY_RSSIMC_0I_PWRDET		B43_PHY_N(0x1A8) /* RSSI multiplication coefficient 0 I power det */
+#define B43_NPHY_RSSIMC_0I_TSSI			B43_PHY_N(0x1A9) /* RSSI multiplication coefficient 0 I TSSI */
+#define B43_NPHY_RSSIMC_0Q_RSSI_X		B43_PHY_N(0x1AA) /* RSSI multiplication coefficient 0 Q RSSI X */
+#define B43_NPHY_RSSIMC_0Q_RSSI_Y		B43_PHY_N(0x1AB) /* RSSI multiplication coefficient 0 Q RSSI Y */
+#define B43_NPHY_RSSIMC_0Q_RSSI_Z		B43_PHY_N(0x1AC) /* RSSI multiplication coefficient 0 Q RSSI Z */
+#define B43_NPHY_RSSIMC_0Q_TBD			B43_PHY_N(0x1AD) /* RSSI multiplication coefficient 0 Q TBD */
+#define B43_NPHY_RSSIMC_0Q_PWRDET		B43_PHY_N(0x1AE) /* RSSI multiplication coefficient 0 Q power det */
+#define B43_NPHY_RSSIMC_0Q_TSSI			B43_PHY_N(0x1AF) /* RSSI multiplication coefficient 0 Q TSSI */
+#define B43_NPHY_RSSIMC_1I_RSSI_X		B43_PHY_N(0x1B0) /* RSSI multiplication coefficient 1 I RSSI X */
+#define B43_NPHY_RSSIMC_1I_RSSI_Y		B43_PHY_N(0x1B1) /* RSSI multiplication coefficient 1 I RSSI Y */
+#define B43_NPHY_RSSIMC_1I_RSSI_Z		B43_PHY_N(0x1B2) /* RSSI multiplication coefficient 1 I RSSI Z */
+#define B43_NPHY_RSSIMC_1I_TBD			B43_PHY_N(0x1B3) /* RSSI multiplication coefficient 1 I TBD */
+#define B43_NPHY_RSSIMC_1I_PWRDET		B43_PHY_N(0x1B4) /* RSSI multiplication coefficient 1 I power det */
+#define B43_NPHY_RSSIMC_1I_TSSI			B43_PHY_N(0x1B5) /* RSSI multiplication coefficient 1 I TSSI */
+#define B43_NPHY_RSSIMC_1Q_RSSI_X		B43_PHY_N(0x1B6) /* RSSI multiplication coefficient 1 Q RSSI X */
+#define B43_NPHY_RSSIMC_1Q_RSSI_Y		B43_PHY_N(0x1B7) /* RSSI multiplication coefficient 1 Q RSSI Y */
+#define B43_NPHY_RSSIMC_1Q_RSSI_Z		B43_PHY_N(0x1B8) /* RSSI multiplication coefficient 1 Q RSSI Z */
+#define B43_NPHY_RSSIMC_1Q_TBD			B43_PHY_N(0x1B9) /* RSSI multiplication coefficient 1 Q TBD */
+#define B43_NPHY_RSSIMC_1Q_PWRDET		B43_PHY_N(0x1BA) /* RSSI multiplication coefficient 1 Q power det */
+#define B43_NPHY_RSSIMC_1Q_TSSI			B43_PHY_N(0x1BB) /* RSSI multiplication coefficient 1 Q TSSI */
+#define B43_NPHY_SAMC_WCNT			B43_PHY_N(0x1BC) /* Sample collect wait counter */
+#define B43_NPHY_PTHROUGH_CNT			B43_PHY_N(0x1BD) /* Pass-through counter */
+#define B43_NPHY_LTRN_OFF_G20L			B43_PHY_N(0x1C4) /* LTRN offset gain 20L */
+#define B43_NPHY_LTRN_OFF_20L			B43_PHY_N(0x1C5) /* LTRN offset 20L */
+#define B43_NPHY_LTRN_OFF_G20U			B43_PHY_N(0x1C6) /* LTRN offset gain 20U */
+#define B43_NPHY_LTRN_OFF_20U			B43_PHY_N(0x1C7) /* LTRN offset 20U */
+#define B43_NPHY_DSSSCCK_GAINSL			B43_PHY_N(0x1C8) /* DSSS/CCK gain settle length */
+#define B43_NPHY_GPIO_LOOUT			B43_PHY_N(0x1C9) /* GPIO low out */
+#define B43_NPHY_GPIO_HIOUT			B43_PHY_N(0x1CA) /* GPIO high out */
+#define B43_NPHY_CRS_CHECK			B43_PHY_N(0x1CB) /* CRS check */
+#define B43_NPHY_ML_LOGSS_RAT			B43_PHY_N(0x1CC) /* ML/logss ratio */
+#define B43_NPHY_DUPSCALE			B43_PHY_N(0x1CD) /* Dup scale */
+#define B43_NPHY_BW1A				B43_PHY_N(0x1CE) /* BW 1A */
+#define B43_NPHY_BW2				B43_PHY_N(0x1CF) /* BW 2 */
+#define B43_NPHY_BW3				B43_PHY_N(0x1D0) /* BW 3 */
+#define B43_NPHY_BW4				B43_PHY_N(0x1D1) /* BW 4 */
+#define B43_NPHY_BW5				B43_PHY_N(0x1D2) /* BW 5 */
+#define B43_NPHY_BW6				B43_PHY_N(0x1D3) /* BW 6 */
+#define B43_NPHY_COALEN0			B43_PHY_N(0x1D4) /* Coarse length 0 */
+#define B43_NPHY_COALEN1			B43_PHY_N(0x1D5) /* Coarse length 1 */
+#define B43_NPHY_CRSTHRES_1U			B43_PHY_N(0x1D6) /* CRS threshold 1 U */
+#define B43_NPHY_CRSTHRES_2U			B43_PHY_N(0x1D7) /* CRS threshold 2 U */
+#define B43_NPHY_CRSTHRES_3U			B43_PHY_N(0x1D8) /* CRS threshold 3 U */
+#define B43_NPHY_CRSCTL_U			B43_PHY_N(0x1D9) /* CRS control U */
+#define B43_NPHY_CRSTHRES_1L			B43_PHY_N(0x1DA) /* CRS threshold 1 L */
+#define B43_NPHY_CRSTHRES_2L			B43_PHY_N(0x1DB) /* CRS threshold 2 L */
+#define B43_NPHY_CRSTHRES_3L			B43_PHY_N(0x1DC) /* CRS threshold 3 L */
+#define B43_NPHY_CRSCTL_L			B43_PHY_N(0x1DD) /* CRS control L */
+#define B43_NPHY_STRA_1U			B43_PHY_N(0x1DE) /* STR address 1 U */
+#define B43_NPHY_STRA_2U			B43_PHY_N(0x1DF) /* STR address 2 U */
+#define B43_NPHY_STRA_1L			B43_PHY_N(0x1E0) /* STR address 1 L */
+#define B43_NPHY_STRA_2L			B43_PHY_N(0x1E1) /* STR address 2 L */
+#define B43_NPHY_CRSCHECK1			B43_PHY_N(0x1E2) /* CRS check 1 */
+#define B43_NPHY_CRSCHECK2			B43_PHY_N(0x1E3) /* CRS check 2 */
+#define B43_NPHY_CRSCHECK3			B43_PHY_N(0x1E4) /* CRS check 3 */
+#define B43_NPHY_JMPSTP0			B43_PHY_N(0x1E5) /* Jump step 0 */
+#define B43_NPHY_JMPSTP1			B43_PHY_N(0x1E6) /* Jump step 1 */
+#define B43_NPHY_TXPCTL_CMD			B43_PHY_N(0x1E7) /* TX power control command */
+#define  B43_NPHY_TXPCTL_CMD_INIT		0x007F /* Init */
+#define  B43_NPHY_TXPCTL_CMD_INIT_SHIFT		0
+#define  B43_NPHY_TXPCTL_CMD_COEFF		0x2000 /* Power control coefficients */
+#define  B43_NPHY_TXPCTL_CMD_HWPCTLEN		0x4000 /* Hardware TX power control enable */
+#define  B43_NPHY_TXPCTL_CMD_PCTLEN		0x8000 /* TX power control enable */
+#define B43_NPHY_TXPCTL_N			B43_PHY_N(0x1E8) /* TX power control N num */
+#define  B43_NPHY_TXPCTL_N_TSSID		0x00FF /* N TSSI delay */
+#define  B43_NPHY_TXPCTL_N_TSSID_SHIFT		0
+#define  B43_NPHY_TXPCTL_N_NPTIL2		0x0700 /* N PT integer log2 */
+#define  B43_NPHY_TXPCTL_N_NPTIL2_SHIFT		8
+#define B43_NPHY_TXPCTL_ITSSI			B43_PHY_N(0x1E9) /* TX power control idle TSSI */
+#define  B43_NPHY_TXPCTL_ITSSI_0		0x003F /* Idle TSSI 0 */
+#define  B43_NPHY_TXPCTL_ITSSI_0_SHIFT		0
+#define  B43_NPHY_TXPCTL_ITSSI_1		0x3F00 /* Idle TSSI 1 */
+#define  B43_NPHY_TXPCTL_ITSSI_1_SHIFT		8
+#define  B43_NPHY_TXPCTL_ITSSI_BINF		0x8000 /* Raw TSSI offset bin format */
+#define B43_NPHY_TXPCTL_TPWR			B43_PHY_N(0x1EA) /* TX power control target power */
+#define  B43_NPHY_TXPCTL_TPWR_0			0x00FF /* Power 0 */
+#define  B43_NPHY_TXPCTL_TPWR_0_SHIFT		0
+#define  B43_NPHY_TXPCTL_TPWR_1			0xFF00 /* Power 1 */
+#define  B43_NPHY_TXPCTL_TPWR_1_SHIFT		8
+#define B43_NPHY_TXPCTL_BIDX			B43_PHY_N(0x1EB) /* TX power control base index */
+#define  B43_NPHY_TXPCTL_BIDX_0			0x007F /* uC base index 0 */
+#define  B43_NPHY_TXPCTL_BIDX_0_SHIFT		0
+#define  B43_NPHY_TXPCTL_BIDX_1			0x7F00 /* uC base index 1 */
+#define  B43_NPHY_TXPCTL_BIDX_1_SHIFT		8
+#define  B43_NPHY_TXPCTL_BIDX_LOAD		0x8000 /* Load base index */
+#define B43_NPHY_TXPCTL_PIDX			B43_PHY_N(0x1EC) /* TX power control power index */
+#define  B43_NPHY_TXPCTL_PIDX_0			0x007F /* uC power index 0 */
+#define  B43_NPHY_TXPCTL_PIDX_0_SHIFT		0
+#define  B43_NPHY_TXPCTL_PIDX_1			0x7F00 /* uC power index 1 */
+#define  B43_NPHY_TXPCTL_PIDX_1_SHIFT		8
+#define B43_NPHY_C1_TXPCTL_STAT			B43_PHY_N(0x1ED) /* Core 1 TX power control status */
+#define B43_NPHY_C2_TXPCTL_STAT			B43_PHY_N(0x1EE) /* Core 2 TX power control status */
+#define  B43_NPHY_TXPCTL_STAT_EST		0x00FF /* Estimated power */
+#define  B43_NPHY_TXPCTL_STAT_EST_SHIFT		0
+#define  B43_NPHY_TXPCTL_STAT_BIDX		0x7F00 /* Base index */
+#define  B43_NPHY_TXPCTL_STAT_BIDX_SHIFT	8
+#define  B43_NPHY_TXPCTL_STAT_ESTVALID		0x8000 /* Estimated power valid */
+#define B43_NPHY_SMALLSGS_LEN			B43_PHY_N(0x1EF) /* Small sig gain settle length */
+#define B43_NPHY_PHYSTAT_GAIN0			B43_PHY_N(0x1F0) /* PHY stats gain info 0 */
+#define B43_NPHY_PHYSTAT_GAIN1			B43_PHY_N(0x1F1) /* PHY stats gain info 1 */
+#define B43_NPHY_PHYSTAT_FREQEST		B43_PHY_N(0x1F2) /* PHY stats frequency estimate */
+#define B43_NPHY_PHYSTAT_ADVRET			B43_PHY_N(0x1F3) /* PHY stats ADV retard */
+#define B43_NPHY_PHYLB_MODE			B43_PHY_N(0x1F4) /* PHY loopback mode */
+#define B43_NPHY_TONE_MIDX20_1			B43_PHY_N(0x1F5) /* Tone map index 20/1 */
+#define B43_NPHY_TONE_MIDX20_2			B43_PHY_N(0x1F6) /* Tone map index 20/2 */
+#define B43_NPHY_TONE_MIDX20_3			B43_PHY_N(0x1F7) /* Tone map index 20/3 */
+#define B43_NPHY_TONE_MIDX40_1			B43_PHY_N(0x1F8) /* Tone map index 40/1 */
+#define B43_NPHY_TONE_MIDX40_2			B43_PHY_N(0x1F9) /* Tone map index 40/2 */
+#define B43_NPHY_TONE_MIDX40_3			B43_PHY_N(0x1FA) /* Tone map index 40/3 */
+#define B43_NPHY_TONE_MIDX40_4			B43_PHY_N(0x1FB) /* Tone map index 40/4 */
+#define B43_NPHY_PILTONE_MIDX1			B43_PHY_N(0x1FC) /* Pilot tone map index 1 */
+#define B43_NPHY_PILTONE_MIDX2			B43_PHY_N(0x1FD) /* Pilot tone map index 2 */
+#define B43_NPHY_PILTONE_MIDX3			B43_PHY_N(0x1FE) /* Pilot tone map index 3 */
+#define B43_NPHY_TXRIFS_FRDEL			B43_PHY_N(0x1FF) /* TX RIFS frame delay */
+#define B43_NPHY_AFESEQ_RX2TX_PUD_40M		B43_PHY_N(0x200) /* AFE seq rx2tx power up/down delay 40M */
+#define B43_NPHY_AFESEQ_TX2RX_PUD_40M		B43_PHY_N(0x201) /* AFE seq tx2rx power up/down delay 40M */
+#define B43_NPHY_AFESEQ_RX2TX_PUD_20M		B43_PHY_N(0x202) /* AFE seq rx2tx power up/down delay 20M */
+#define B43_NPHY_AFESEQ_TX2RX_PUD_20M		B43_PHY_N(0x203) /* AFE seq tx2rx power up/down delay 20M */
+#define B43_NPHY_RX_SIGCTL			B43_PHY_N(0x204) /* RX signal control */
+#define B43_NPHY_RXPIL_CYCNT0			B43_PHY_N(0x205) /* RX pilot cycle counter 0 */
+#define B43_NPHY_RXPIL_CYCNT1			B43_PHY_N(0x206) /* RX pilot cycle counter 1 */
+#define B43_NPHY_RXPIL_CYCNT2			B43_PHY_N(0x207) /* RX pilot cycle counter 2 */
+#define B43_NPHY_AFESEQ_RX2TX_PUD_10M		B43_PHY_N(0x208) /* AFE seq rx2tx power up/down delay 10M */
+#define B43_NPHY_AFESEQ_TX2RX_PUD_10M		B43_PHY_N(0x209) /* AFE seq tx2rx power up/down delay 10M */
+#define B43_NPHY_DSSSCCK_CRSEXTL		B43_PHY_N(0x20A) /* DSSS/CCK CRS extension length */
+#define B43_NPHY_ML_LOGSS_RATSLOPE		B43_PHY_N(0x20B) /* ML/logss ratio slope */
+#define B43_NPHY_RIFS_SRCTL			B43_PHY_N(0x20C) /* RIFS search timeout length */
+#define B43_NPHY_TXREALFD			B43_PHY_N(0x20D) /* TX real frame delay */
+#define B43_NPHY_HPANT_SWTHRES			B43_PHY_N(0x20E) /* High power antenna switch threshold */
+#define B43_NPHY_EDCRS_ASSTHRES0		B43_PHY_N(0x210) /* ED CRS assert threshold 0 */
+#define B43_NPHY_EDCRS_ASSTHRES1		B43_PHY_N(0x211) /* ED CRS assert threshold 1 */
+#define B43_NPHY_EDCRS_DEASSTHRES0		B43_PHY_N(0x212) /* ED CRS deassert threshold 0 */
+#define B43_NPHY_EDCRS_DEASSTHRES1		B43_PHY_N(0x213) /* ED CRS deassert threshold 1 */
+#define B43_NPHY_STR_WTIME20U			B43_PHY_N(0x214) /* STR wait time 20U */
+#define B43_NPHY_STR_WTIME20L			B43_PHY_N(0x215) /* STR wait time 20L */
+#define B43_NPHY_TONE_MIDX657M			B43_PHY_N(0x216) /* Tone map index 657M */
+#define B43_NPHY_HTSIGTONES			B43_PHY_N(0x217) /* HT signal tones */
+#define B43_NPHY_RSSI1				B43_PHY_N(0x219) /* RSSI value 1 */
+#define B43_NPHY_RSSI2				B43_PHY_N(0x21A) /* RSSI value 2 */
+#define B43_NPHY_CHAN_ESTHANG			B43_PHY_N(0x21D) /* Channel estimate hang */
+#define B43_NPHY_FINERX2_CGC			B43_PHY_N(0x221) /* Fine RX 2 clock gate control */
+#define  B43_NPHY_FINERX2_CGC_DECGC		0x0008 /* Decode gated clocks */
+#define B43_NPHY_TXPCTL_INIT			B43_PHY_N(0x222) /* TX power controll init */
+#define  B43_NPHY_TXPCTL_INIT_PIDXI1		0x00FF /* Power index init 1 */
+#define  B43_NPHY_TXPCTL_INIT_PIDXI1_SHIFT	0
+
+
+
+/* Broadcom 2055 radio registers */
+
+#define B2055_GEN_SPARE			0x00 /* GEN spare */
+#define B2055_SP_PINPD			0x02 /* SP PIN PD */
+#define B2055_C1_SP_RSSI		0x03 /* SP RSSI Core 1 */
+#define B2055_C1_SP_PDMISC		0x04 /* SP PD MISC Core 1 */
+#define B2055_C2_SP_RSSI		0x05 /* SP RSSI Core 2 */
+#define B2055_C2_SP_PDMISC		0x06 /* SP PD MISC Core 2 */
+#define B2055_C1_SP_RXGC1		0x07 /* SP RX GC1 Core 1 */
+#define B2055_C1_SP_RXGC2		0x08 /* SP RX GC2 Core 1 */
+#define B2055_C2_SP_RXGC1		0x09 /* SP RX GC1 Core 2 */
+#define B2055_C2_SP_RXGC2		0x0A /* SP RX GC2 Core 2 */
+#define B2055_C1_SP_LPFBWSEL		0x0B /* SP LPF BW select Core 1 */
+#define B2055_C2_SP_LPFBWSEL		0x0C /* SP LPF BW select Core 2 */
+#define B2055_C1_SP_TXGC1		0x0D /* SP TX GC1 Core 1 */
+#define B2055_C1_SP_TXGC2		0x0E /* SP TX GC2 Core 1 */
+#define B2055_C2_SP_TXGC1		0x0F /* SP TX GC1 Core 2 */
+#define B2055_C2_SP_TXGC2		0x10 /* SP TX GC2 Core 2 */
+#define B2055_MASTER1			0x11 /* Master control 1 */
+#define B2055_MASTER2			0x12 /* Master control 2 */
+#define B2055_PD_LGEN			0x13 /* PD LGEN */
+#define B2055_PD_PLLTS			0x14 /* PD PLL TS */
+#define B2055_C1_PD_LGBUF		0x15 /* PD Core 1 LGBUF */
+#define B2055_C1_PD_TX			0x16 /* PD Core 1 TX */
+#define B2055_C1_PD_RXTX		0x17 /* PD Core 1 RXTX */
+#define B2055_C1_PD_RSSIMISC		0x18 /* PD Core 1 RSSI MISC */
+#define B2055_C2_PD_LGBUF		0x19 /* PD Core 2 LGBUF */
+#define B2055_C2_PD_TX			0x1A /* PD Core 2 TX */
+#define B2055_C2_PD_RXTX		0x1B /* PD Core 2 RXTX */
+#define B2055_C2_PD_RSSIMISC		0x1C /* PD Core 2 RSSI MISC */
+#define B2055_PWRDET_LGEN		0x1D /* PWRDET LGEN */
+#define B2055_C1_PWRDET_LGBUF		0x1E /* PWRDET LGBUF Core 1 */
+#define B2055_C1_PWRDET_RXTX		0x1F /* PWRDET RXTX Core 1 */
+#define B2055_C2_PWRDET_LGBUF		0x20 /* PWRDET LGBUF Core 2 */
+#define B2055_C2_PWRDET_RXTX		0x21 /* PWRDET RXTX Core 2 */
+#define B2055_RRCCAL_CS			0x22 /* RRCCAL Control spare */
+#define B2055_RRCCAL_NOPTSEL		0x23 /* RRCCAL N OPT SEL */
+#define B2055_CAL_MISC			0x24 /* CAL MISC */
+#define B2055_CAL_COUT			0x25 /* CAL Counter out */
+#define B2055_CAL_COUT2			0x26 /* CAL Counter out 2 */
+#define B2055_CAL_CVARCTL		0x27 /* CAL CVAR Control */
+#define B2055_CAL_RVARCTL		0x28 /* CAL RVAR Control */
+#define B2055_CAL_LPOCTL		0x29 /* CAL LPO Control */
+#define B2055_CAL_TS			0x2A /* CAL TS */
+#define B2055_CAL_RCCALRTS		0x2B /* CAL RCCAL READ TS */
+#define B2055_CAL_RCALRTS		0x2C /* CAL RCAL READ TS */
+#define B2055_PADDRV			0x2D /* PAD driver */
+#define B2055_XOCTL1			0x2E /* XO Control 1 */
+#define B2055_XOCTL2			0x2F /* XO Control 2 */
+#define B2055_XOREGUL			0x30 /* XO Regulator */
+#define B2055_XOMISC			0x31 /* XO misc */
+#define B2055_PLL_LFC1			0x32 /* PLL LF C1 */
+#define B2055_PLL_CALVTH		0x33 /* PLL CAL VTH */
+#define B2055_PLL_LFC2			0x34 /* PLL LF C2 */
+#define B2055_PLL_REF			0x35 /* PLL reference */
+#define B2055_PLL_LFR1			0x36 /* PLL LF R1 */
+#define B2055_PLL_PFDCP			0x37 /* PLL PFD CP */
+#define B2055_PLL_IDAC_CPOPAMP		0x38 /* PLL IDAC CPOPAMP */
+#define B2055_PLL_CPREG			0x39 /* PLL CP Regulator */
+#define B2055_PLL_RCAL			0x3A /* PLL RCAL */
+#define B2055_RF_PLLMOD0		0x3B /* RF PLL MOD0 */
+#define B2055_RF_PLLMOD1		0x3C /* RF PLL MOD1 */
+#define B2055_RF_MMDIDAC1		0x3D /* RF MMD IDAC 1 */
+#define B2055_RF_MMDIDAC0		0x3E /* RF MMD IDAC 0 */
+#define B2055_RF_MMDSP			0x3F /* RF MMD spare */
+#define B2055_VCO_CAL1			0x40 /* VCO cal 1 */
+#define B2055_VCO_CAL2			0x41 /* VCO cal 2 */
+#define B2055_VCO_CAL3			0x42 /* VCO cal 3 */
+#define B2055_VCO_CAL4			0x43 /* VCO cal 4 */
+#define B2055_VCO_CAL5			0x44 /* VCO cal 5 */
+#define B2055_VCO_CAL6			0x45 /* VCO cal 6 */
+#define B2055_VCO_CAL7			0x46 /* VCO cal 7 */
+#define B2055_VCO_CAL8			0x47 /* VCO cal 8 */
+#define B2055_VCO_CAL9			0x48 /* VCO cal 9 */
+#define B2055_VCO_CAL10			0x49 /* VCO cal 10 */
+#define B2055_VCO_CAL11			0x4A /* VCO cal 11 */
+#define B2055_VCO_CAL12			0x4B /* VCO cal 12 */
+#define B2055_VCO_CAL13			0x4C /* VCO cal 13 */
+#define B2055_VCO_CAL14			0x4D /* VCO cal 14 */
+#define B2055_VCO_CAL15			0x4E /* VCO cal 15 */
+#define B2055_VCO_CAL16			0x4F /* VCO cal 16 */
+#define B2055_VCO_KVCO			0x50 /* VCO KVCO */
+#define B2055_VCO_CAPTAIL		0x51 /* VCO CAP TAIL */
+#define B2055_VCO_IDACVCO		0x52 /* VCO IDAC VCO */
+#define B2055_VCO_REG			0x53 /* VCO Regulator */
+#define B2055_PLL_RFVTH			0x54 /* PLL RF VTH */
+#define B2055_LGBUF_CENBUF		0x55 /* LGBUF CEN BUF */
+#define B2055_LGEN_TUNE1		0x56 /* LGEN tune 1 */
+#define B2055_LGEN_TUNE2		0x57 /* LGEN tune 2 */
+#define B2055_LGEN_IDAC1		0x58 /* LGEN IDAC 1 */
+#define B2055_LGEN_IDAC2		0x59 /* LGEN IDAC 2 */
+#define B2055_LGEN_BIASC		0x5A /* LGEN BIAS counter */
+#define B2055_LGEN_BIASIDAC		0x5B /* LGEN BIAS IDAC */
+#define B2055_LGEN_RCAL			0x5C /* LGEN RCAL */
+#define B2055_LGEN_DIV			0x5D /* LGEN div */
+#define B2055_LGEN_SPARE2		0x5E /* LGEN spare 2 */
+#define B2055_C1_LGBUF_ATUNE		0x5F /* Core 1 LGBUF A tune */
+#define B2055_C1_LGBUF_GTUNE		0x60 /* Core 1 LGBUF G tune */
+#define B2055_C1_LGBUF_DIV		0x61 /* Core 1 LGBUF div */
+#define B2055_C1_LGBUF_AIDAC		0x62 /* Core 1 LGBUF A IDAC */
+#define B2055_C1_LGBUF_GIDAC		0x63 /* Core 1 LGBUF G IDAC */
+#define B2055_C1_LGBUF_IDACFO		0x64 /* Core 1 LGBUF IDAC filter override */
+#define B2055_C1_LGBUF_SPARE		0x65 /* Core 1 LGBUF spare */
+#define B2055_C1_RX_RFSPC1		0x66 /* Core 1 RX RF SPC1 */
+#define B2055_C1_RX_RFR1		0x67 /* Core 1 RX RF reg 1 */
+#define B2055_C1_RX_RFR2		0x68 /* Core 1 RX RF reg 2 */
+#define B2055_C1_RX_RFRCAL		0x69 /* Core 1 RX RF RCAL */
+#define B2055_C1_RX_BB_BLCMP		0x6A /* Core 1 RX Baseband BUFI LPF CMP */
+#define B2055_C1_RX_BB_LPF		0x6B /* Core 1 RX Baseband LPF */
+#define B2055_C1_RX_BB_MIDACHP		0x6C /* Core 1 RX Baseband MIDAC High-pass */
+#define B2055_C1_RX_BB_VGA1IDAC		0x6D /* Core 1 RX Baseband VGA1 IDAC */
+#define B2055_C1_RX_BB_VGA2IDAC		0x6E /* Core 1 RX Baseband VGA2 IDAC */
+#define B2055_C1_RX_BB_VGA3IDAC		0x6F /* Core 1 RX Baseband VGA3 IDAC */
+#define B2055_C1_RX_BB_BUFOCTL		0x70 /* Core 1 RX Baseband BUFO Control */
+#define B2055_C1_RX_BB_RCCALCTL		0x71 /* Core 1 RX Baseband RCCAL Control */
+#define B2055_C1_RX_BB_RSSICTL1		0x72 /* Core 1 RX Baseband RSSI Control 1 */
+#define B2055_C1_RX_BB_RSSICTL2		0x73 /* Core 1 RX Baseband RSSI Control 2 */
+#define B2055_C1_RX_BB_RSSICTL3		0x74 /* Core 1 RX Baseband RSSI Control 3 */
+#define B2055_C1_RX_BB_RSSICTL4		0x75 /* Core 1 RX Baseband RSSI Control 4 */
+#define B2055_C1_RX_BB_RSSICTL5		0x76 /* Core 1 RX Baseband RSSI Control 5 */
+#define B2055_C1_RX_BB_REG		0x77 /* Core 1 RX Baseband Regulator */
+#define B2055_C1_RX_BB_SPARE1		0x78 /* Core 1 RX Baseband spare 1 */
+#define B2055_C1_RX_TXBBRCAL		0x79 /* Core 1 RX TX BB RCAL */
+#define B2055_C1_TX_RF_SPGA		0x7A /* Core 1 TX RF SGM PGA */
+#define B2055_C1_TX_RF_SPAD		0x7B /* Core 1 TX RF SGM PAD */
+#define B2055_C1_TX_RF_CNTPGA1		0x7C /* Core 1 TX RF counter PGA 1 */
+#define B2055_C1_TX_RF_CNTPAD1		0x7D /* Core 1 TX RF counter PAD 1 */
+#define B2055_C1_TX_RF_PGAIDAC		0x7E /* Core 1 TX RF PGA IDAC */
+#define B2055_C1_TX_PGAPADTN		0x7F /* Core 1 TX PGA PAD TN */
+#define B2055_C1_TX_PADIDAC1		0x80 /* Core 1 TX PAD IDAC 1 */
+#define B2055_C1_TX_PADIDAC2		0x81 /* Core 1 TX PAD IDAC 2 */
+#define B2055_C1_TX_MXBGTRIM		0x82 /* Core 1 TX MX B/G TRIM */
+#define B2055_C1_TX_RF_RCAL		0x83 /* Core 1 TX RF RCAL */
+#define B2055_C1_TX_RF_PADTSSI1		0x84 /* Core 1 TX RF PAD TSSI1 */
+#define B2055_C1_TX_RF_PADTSSI2		0x85 /* Core 1 TX RF PAD TSSI2 */
+#define B2055_C1_TX_RF_SPARE		0x86 /* Core 1 TX RF spare */
+#define B2055_C1_TX_RF_IQCAL1		0x87 /* Core 1 TX RF I/Q CAL 1 */
+#define B2055_C1_TX_RF_IQCAL2		0x88 /* Core 1 TX RF I/Q CAL 2 */
+#define B2055_C1_TXBB_RCCAL		0x89 /* Core 1 TXBB RC CAL Control */
+#define B2055_C1_TXBB_LPF1		0x8A /* Core 1 TXBB LPF 1 */
+#define B2055_C1_TX_VOSCNCL		0x8B /* Core 1 TX VOS CNCL */
+#define B2055_C1_TX_LPF_MXGMIDAC	0x8C /* Core 1 TX LPF MXGM IDAC */
+#define B2055_C1_TX_BB_MXGM		0x8D /* Core 1 TX BB MXGM */
+#define B2055_C2_LGBUF_ATUNE		0x8E /* Core 2 LGBUF A tune */
+#define B2055_C2_LGBUF_GTUNE		0x8F /* Core 2 LGBUF G tune */
+#define B2055_C2_LGBUF_DIV		0x90 /* Core 2 LGBUF div */
+#define B2055_C2_LGBUF_AIDAC		0x91 /* Core 2 LGBUF A IDAC */
+#define B2055_C2_LGBUF_GIDAC		0x92 /* Core 2 LGBUF G IDAC */
+#define B2055_C2_LGBUF_IDACFO		0x93 /* Core 2 LGBUF IDAC filter override */
+#define B2055_C2_LGBUF_SPARE		0x94 /* Core 2 LGBUF spare */
+#define B2055_C2_RX_RFSPC1		0x95 /* Core 2 RX RF SPC1 */
+#define B2055_C2_RX_RFR1		0x96 /* Core 2 RX RF reg 1 */
+#define B2055_C2_RX_RFR2		0x97 /* Core 2 RX RF reg 2 */
+#define B2055_C2_RX_RFRCAL		0x98 /* Core 2 RX RF RCAL */
+#define B2055_C2_RX_BB_BLCMP		0x99 /* Core 2 RX Baseband BUFI LPF CMP */
+#define B2055_C2_RX_BB_LPF		0x9A /* Core 2 RX Baseband LPF */
+#define B2055_C2_RX_BB_MIDACHP		0x9B /* Core 2 RX Baseband MIDAC High-pass */
+#define B2055_C2_RX_BB_VGA1IDAC		0x9C /* Core 2 RX Baseband VGA1 IDAC */
+#define B2055_C2_RX_BB_VGA2IDAC		0x9D /* Core 2 RX Baseband VGA2 IDAC */
+#define B2055_C2_RX_BB_VGA3IDAC		0x9E /* Core 2 RX Baseband VGA3 IDAC */
+#define B2055_C2_RX_BB_BUFOCTL		0x9F /* Core 2 RX Baseband BUFO Control */
+#define B2055_C2_RX_BB_RCCALCTL		0xA0 /* Core 2 RX Baseband RCCAL Control */
+#define B2055_C2_RX_BB_RSSICTL1		0xA1 /* Core 2 RX Baseband RSSI Control 1 */
+#define B2055_C2_RX_BB_RSSICTL2		0xA2 /* Core 2 RX Baseband RSSI Control 2 */
+#define B2055_C2_RX_BB_RSSICTL3		0xA3 /* Core 2 RX Baseband RSSI Control 3 */
+#define B2055_C2_RX_BB_RSSICTL4		0xA4 /* Core 2 RX Baseband RSSI Control 4 */
+#define B2055_C2_RX_BB_RSSICTL5		0xA5 /* Core 2 RX Baseband RSSI Control 5 */
+#define B2055_C2_RX_BB_REG		0xA6 /* Core 2 RX Baseband Regulator */
+#define B2055_C2_RX_BB_SPARE1		0xA7 /* Core 2 RX Baseband spare 1 */
+#define B2055_C2_RX_TXBBRCAL		0xA8 /* Core 2 RX TX BB RCAL */
+#define B2055_C2_TX_RF_SPGA		0xA9 /* Core 2 TX RF SGM PGA */
+#define B2055_C2_TX_RF_SPAD		0xAA /* Core 2 TX RF SGM PAD */
+#define B2055_C2_TX_RF_CNTPGA1		0xAB /* Core 2 TX RF counter PGA 1 */
+#define B2055_C2_TX_RF_CNTPAD1		0xAC /* Core 2 TX RF counter PAD 1 */
+#define B2055_C2_TX_RF_PGAIDAC		0xAD /* Core 2 TX RF PGA IDAC */
+#define B2055_C2_TX_PGAPADTN		0xAE /* Core 2 TX PGA PAD TN */
+#define B2055_C2_TX_PADIDAC1		0xAF /* Core 2 TX PAD IDAC 1 */
+#define B2055_C2_TX_PADIDAC2		0xB0 /* Core 2 TX PAD IDAC 2 */
+#define B2055_C2_TX_MXBGTRIM		0xB1 /* Core 2 TX MX B/G TRIM */
+#define B2055_C2_TX_RF_RCAL		0xB2 /* Core 2 TX RF RCAL */
+#define B2055_C2_TX_RF_PADTSSI1		0xB3 /* Core 2 TX RF PAD TSSI1 */
+#define B2055_C2_TX_RF_PADTSSI2		0xB4 /* Core 2 TX RF PAD TSSI2 */
+#define B2055_C2_TX_RF_SPARE		0xB5 /* Core 2 TX RF spare */
+#define B2055_C2_TX_RF_IQCAL1		0xB6 /* Core 2 TX RF I/Q CAL 1 */
+#define B2055_C2_TX_RF_IQCAL2		0xB7 /* Core 2 TX RF I/Q CAL 2 */
+#define B2055_C2_TXBB_RCCAL		0xB8 /* Core 2 TXBB RC CAL Control */
+#define B2055_C2_TXBB_LPF1		0xB9 /* Core 2 TXBB LPF 1 */
+#define B2055_C2_TX_VOSCNCL		0xBA /* Core 2 TX VOS CNCL */
+#define B2055_C2_TX_LPF_MXGMIDAC	0xBB /* Core 2 TX LPF MXGM IDAC */
+#define B2055_C2_TX_BB_MXGM		0xBC /* Core 2 TX BB MXGM */
+#define B2055_PRG_GCHP21		0xBD /* PRG GC HPVGA23 21 */
+#define B2055_PRG_GCHP22		0xBE /* PRG GC HPVGA23 22 */
+#define B2055_PRG_GCHP23		0xBF /* PRG GC HPVGA23 23 */
+#define B2055_PRG_GCHP24		0xC0 /* PRG GC HPVGA23 24 */
+#define B2055_PRG_GCHP25		0xC1 /* PRG GC HPVGA23 25 */
+#define B2055_PRG_GCHP26		0xC2 /* PRG GC HPVGA23 26 */
+#define B2055_PRG_GCHP27		0xC3 /* PRG GC HPVGA23 27 */
+#define B2055_PRG_GCHP28		0xC4 /* PRG GC HPVGA23 28 */
+#define B2055_PRG_GCHP29		0xC5 /* PRG GC HPVGA23 29 */
+#define B2055_PRG_GCHP30		0xC6 /* PRG GC HPVGA23 30 */
+#define B2055_C1_LNA_GAINBST		0xCD /* Core 1 LNA GAINBST */
+#define B2055_C1_B0NB_RSSIVCM		0xD2 /* Core 1 B0 narrow-band RSSI VCM */
+#define B2055_C1_GENSPARE2		0xD6 /* Core 1 GEN spare 2 */
+#define B2055_C2_LNA_GAINBST		0xD9 /* Core 2 LNA GAINBST */
+#define B2055_C2_B0NB_RSSIVCM		0xDE /* Core 2 B0 narrow-band RSSI VCM */
+#define B2055_C2_GENSPARE2		0xE2 /* Core 2 GEN spare 2 */
+
+
+
+struct b43_wldev;
+
+int b43_phy_initn(struct b43_wldev *dev);
+
+void b43_nphy_radio_turn_on(struct b43_wldev *dev);
+void b43_nphy_radio_turn_off(struct b43_wldev *dev);
+
+int b43_nphy_selectchannel(struct b43_wldev *dev, u8 channel);
+
+void b43_nphy_xmitpower(struct b43_wldev *dev);
+void b43_nphy_set_rxantenna(struct b43_wldev *dev, int antenna);
+
+#endif /* B43_NPHY_H_ */
diff --git a/package/b43/src/pcmcia.c b/package/b43/src/pcmcia.c
index b242a9a90d..b79a6bd539 100644
--- a/package/b43/src/pcmcia.c
+++ b/package/b43/src/pcmcia.c
@@ -65,12 +65,12 @@ static int __devinit b43_pcmcia_probe(struct pcmcia_device *dev)
 	tuple_t tuple;
 	cisparse_t parse;
 	int err = -ENOMEM;
-	int res;
+	int res = 0;
 	unsigned char buf[64];
 
 	ssb = kzalloc(sizeof(*ssb), GFP_KERNEL);
 	if (!ssb)
-		goto out;
+		goto out_error;
 
 	err = -ENODEV;
 	tuple.DesiredTuple = CISTPL_CONFIG;
@@ -96,10 +96,12 @@ static int __devinit b43_pcmcia_probe(struct pcmcia_device *dev)
 	dev->io.NumPorts2 = 0;
 	dev->io.Attributes2 = 0;
 
-	win.Attributes = WIN_MEMORY_TYPE_CM | WIN_ENABLE | WIN_USE_WAIT;
+	win.Attributes = WIN_ADDR_SPACE_MEM | WIN_MEMORY_TYPE_CM |
+			 WIN_ENABLE | WIN_DATA_WIDTH_16 |
+			 WIN_USE_WAIT;
 	win.Base = 0;
 	win.Size = SSB_CORE_SIZE;
-	win.AccessSpeed = 1000;
+	win.AccessSpeed = 250;
 	res = pcmcia_request_window(&dev, &win, &dev->win);
 	if (res != CS_SUCCESS)
 		goto err_kfree_ssb;
@@ -108,21 +110,34 @@ static int __devinit b43_pcmcia_probe(struct pcmcia_device *dev)
 	mem.Page = 0;
 	res = pcmcia_map_mem_page(dev->win, &mem);
 	if (res != CS_SUCCESS)
-		goto err_kfree_ssb;
+		goto err_disable;
+
+	dev->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING | IRQ_FIRST_SHARED;
+	dev->irq.IRQInfo1 = IRQ_LEVEL_ID | IRQ_SHARE_ID;
+	dev->irq.Handler = NULL; /* The handler is registered later. */
+	dev->irq.Instance = NULL;
+	res = pcmcia_request_irq(dev, &dev->irq);
+	if (res != CS_SUCCESS)
+		goto err_disable;
 
 	res = pcmcia_request_configuration(dev, &dev->conf);
 	if (res != CS_SUCCESS)
 		goto err_disable;
 
 	err = ssb_bus_pcmciabus_register(ssb, dev, win.Base);
+	if (err)
+		goto err_disable;
 	dev->priv = ssb;
 
-      out:
-	return err;
-      err_disable:
+	return 0;
+
+err_disable:
 	pcmcia_disable_device(dev);
-      err_kfree_ssb:
+err_kfree_ssb:
 	kfree(ssb);
+out_error:
+	printk(KERN_ERR "b43-pcmcia: Initialization failed (%d, %d)\n",
+	       res, err);
 	return err;
 }
 
@@ -131,22 +146,21 @@ static void __devexit b43_pcmcia_remove(struct pcmcia_device *dev)
 	struct ssb_bus *ssb = dev->priv;
 
 	ssb_bus_unregister(ssb);
-	pcmcia_release_window(dev->win);
 	pcmcia_disable_device(dev);
 	kfree(ssb);
 	dev->priv = NULL;
 }
 
 static struct pcmcia_driver b43_pcmcia_driver = {
-	.owner = THIS_MODULE,
-	.drv = {
-		.name = "b43-pcmcia",
-		},
-	.id_table = b43_pcmcia_tbl,
-	.probe = b43_pcmcia_probe,
-	.remove = b43_pcmcia_remove,
-	.suspend = b43_pcmcia_suspend,
-	.resume = b43_pcmcia_resume,
+	.owner		= THIS_MODULE,
+	.drv		= {
+				.name = "b43-pcmcia",
+			},
+	.id_table	= b43_pcmcia_tbl,
+	.probe		= b43_pcmcia_probe,
+	.remove		= __devexit_p(b43_pcmcia_remove),
+	.suspend	= b43_pcmcia_suspend,
+	.resume		= b43_pcmcia_resume,
 };
 
 int b43_pcmcia_init(void)
diff --git a/package/b43/src/phy.c b/package/b43/src/phy.c
index 3d4ed647c3..71507b260b 100644
--- a/package/b43/src/phy.c
+++ b/package/b43/src/phy.c
@@ -3,7 +3,7 @@
   Broadcom B43 wireless driver
 
   Copyright (c) 2005 Martin Langer <martin-langer@gmx.de>,
-  Copyright (c) 2005, 2006 Stefano Brivio <st3@riseup.net>
+  Copyright (c) 2005-2007 Stefano Brivio <stefano.brivio@polimi.it>
   Copyright (c) 2005, 2006 Michael Buesch <mb@bu3sch.de>
   Copyright (c) 2005, 2006 Danny van Dyk <kugelfang@gentoo.org>
   Copyright (c) 2005, 2006 Andreas Jaggi <andreas.jaggi@waterwave.ch>
@@ -31,9 +31,12 @@
 
 #include "b43.h"
 #include "phy.h"
+#include "nphy.h"
 #include "main.h"
 #include "tables.h"
 #include "lo.h"
+#include "wa.h"
+
 
 static const s8 b43_tssi2dbm_b_table[] = {
 	0x4D, 0x4C, 0x4B, 0x4A,
@@ -225,42 +228,30 @@ static void b43_shm_clear_tssi(struct b43_wldev *dev)
 	}
 }
 
-void b43_raw_phy_lock(struct b43_wldev *dev)
+/* Lock the PHY registers against concurrent access from the microcode.
+ * This lock is nonrecursive. */
+void b43_phy_lock(struct b43_wldev *dev)
 {
-	struct b43_phy *phy = &dev->phy;
-
-	B43_WARN_ON(!irqs_disabled());
-
-	/* We had a check for MACCTL==0 here, but I think that doesn't
-	 * make sense, as MACCTL is never 0 when this is called.
-	 *      --mb */
-	B43_WARN_ON(b43_read32(dev, B43_MMIO_MACCTL) == 0);
+#if B43_DEBUG
+	B43_WARN_ON(dev->phy.phy_locked);
+	dev->phy.phy_locked = 1;
+#endif
+	B43_WARN_ON(dev->dev->id.revision < 3);
 
-	if (dev->dev->id.revision < 3) {
-		b43_mac_suspend(dev);
-		spin_lock(&phy->lock);
-	} else {
-		if (!b43_is_mode(dev->wl, IEEE80211_IF_TYPE_AP))
-			b43_power_saving_ctl_bits(dev, B43_PS_AWAKE);
-	}
-	phy->locked = 1;
+	if (!b43_is_mode(dev->wl, IEEE80211_IF_TYPE_AP))
+		b43_power_saving_ctl_bits(dev, B43_PS_AWAKE);
 }
 
-void b43_raw_phy_unlock(struct b43_wldev *dev)
+void b43_phy_unlock(struct b43_wldev *dev)
 {
-	struct b43_phy *phy = &dev->phy;
+#if B43_DEBUG
+	B43_WARN_ON(!dev->phy.phy_locked);
+	dev->phy.phy_locked = 0;
+#endif
+	B43_WARN_ON(dev->dev->id.revision < 3);
 
-	B43_WARN_ON(!irqs_disabled());
-	if (dev->dev->id.revision < 3) {
-		if (phy->locked) {
-			spin_unlock(&phy->lock);
-			b43_mac_enable(dev);
-		}
-	} else {
-		if (!b43_is_mode(dev->wl, IEEE80211_IF_TYPE_AP))
-			b43_power_saving_ctl_bits(dev, 0);
-	}
-	phy->locked = 0;
+	if (!b43_is_mode(dev->wl, IEEE80211_IF_TYPE_AP))
+		b43_power_saving_ctl_bits(dev, 0);
 }
 
 /* Different PHYs require different register routing flags.
@@ -271,15 +262,30 @@ static inline u16 adjust_phyreg_for_phytype(struct b43_phy *phy,
 {
 	if (phy->type == B43_PHYTYPE_A) {
 		/* OFDM registers are base-registers for the A-PHY. */
-		offset &= ~B43_PHYROUTE_OFDM_GPHY;
+		if ((offset & B43_PHYROUTE) == B43_PHYROUTE_OFDM_GPHY) {
+			offset &= ~B43_PHYROUTE;
+			offset |= B43_PHYROUTE_BASE;
+		}
 	}
-	if (offset & B43_PHYROUTE_EXT_GPHY) {
+
+#if B43_DEBUG
+	if ((offset & B43_PHYROUTE) == B43_PHYROUTE_EXT_GPHY) {
 		/* Ext-G registers are only available on G-PHYs */
 		if (phy->type != B43_PHYTYPE_G) {
-			b43dbg(dev->wl, "EXT-G PHY access at "
-			       "0x%04X on %u type PHY\n", offset, phy->type);
+			b43err(dev->wl, "Invalid EXT-G PHY access at "
+			       "0x%04X on PHY type %u\n", offset, phy->type);
+			dump_stack();
 		}
 	}
+	if ((offset & B43_PHYROUTE) == B43_PHYROUTE_N_BMODE) {
+		/* N-BMODE registers are only available on N-PHYs */
+		if (phy->type != B43_PHYTYPE_N) {
+			b43err(dev->wl, "Invalid N-BMODE PHY access at "
+			       "0x%04X on PHY type %u\n", offset, phy->type);
+			dump_stack();
+		}
+	}
+#endif /* B43_DEBUG */
 
 	return offset;
 }
@@ -299,11 +305,26 @@ void b43_phy_write(struct b43_wldev *dev, u16 offset, u16 val)
 
 	offset = adjust_phyreg_for_phytype(phy, offset, dev);
 	b43_write16(dev, B43_MMIO_PHY_CONTROL, offset);
-	mmiowb();
 	b43_write16(dev, B43_MMIO_PHY_DATA, val);
 }
 
-static void b43_radio_set_txpower_a(struct b43_wldev *dev, u16 txpower);
+void b43_phy_mask(struct b43_wldev *dev, u16 offset, u16 mask)
+{
+	b43_phy_write(dev, offset,
+		      b43_phy_read(dev, offset) & mask);
+}
+
+void b43_phy_set(struct b43_wldev *dev, u16 offset, u16 set)
+{
+	b43_phy_write(dev, offset,
+		      b43_phy_read(dev, offset) | set);
+}
+
+void b43_phy_maskset(struct b43_wldev *dev, u16 offset, u16 mask, u16 set)
+{
+	b43_phy_write(dev, offset,
+		      (b43_phy_read(dev, offset) & mask) | set);
+}
 
 /* Adjust the transmission power output (G-PHY) */
 void b43_set_txpower_g(struct b43_wldev *dev,
@@ -763,366 +784,96 @@ static void b43_phy_init_pctl(struct b43_wldev *dev)
 	b43_shm_clear_tssi(dev);
 }
 
-static void b43_phy_agcsetup(struct b43_wldev *dev)
-{
-	struct b43_phy *phy = &dev->phy;
-	u16 offset = 0x0000;
-
-	if (phy->rev == 1)
-		offset = 0x4C00;
-
-	b43_ofdmtab_write16(dev, offset, 0, 0x00FE);
-	b43_ofdmtab_write16(dev, offset, 1, 0x000D);
-	b43_ofdmtab_write16(dev, offset, 2, 0x0013);
-	b43_ofdmtab_write16(dev, offset, 3, 0x0019);
-
-	if (phy->rev == 1) {
-		b43_ofdmtab_write16(dev, 0x1800, 0, 0x2710);
-		b43_ofdmtab_write16(dev, 0x1801, 0, 0x9B83);
-		b43_ofdmtab_write16(dev, 0x1802, 0, 0x9B83);
-		b43_ofdmtab_write16(dev, 0x1803, 0, 0x0F8D);
-		b43_phy_write(dev, 0x0455, 0x0004);
-	}
-
-	b43_phy_write(dev, 0x04A5, (b43_phy_read(dev, 0x04A5)
-				    & 0x00FF) | 0x5700);
-	b43_phy_write(dev, 0x041A, (b43_phy_read(dev, 0x041A)
-				    & 0xFF80) | 0x000F);
-	b43_phy_write(dev, 0x041A, (b43_phy_read(dev, 0x041A)
-				    & 0xC07F) | 0x2B80);
-	b43_phy_write(dev, 0x048C, (b43_phy_read(dev, 0x048C)
-				    & 0xF0FF) | 0x0300);
-
-	b43_radio_write16(dev, 0x007A, b43_radio_read16(dev, 0x007A)
-			  | 0x0008);
-
-	b43_phy_write(dev, 0x04A0, (b43_phy_read(dev, 0x04A0)
-				    & 0xFFF0) | 0x0008);
-	b43_phy_write(dev, 0x04A1, (b43_phy_read(dev, 0x04A1)
-				    & 0xF0FF) | 0x0600);
-	b43_phy_write(dev, 0x04A2, (b43_phy_read(dev, 0x04A2)
-				    & 0xF0FF) | 0x0700);
-	b43_phy_write(dev, 0x04A0, (b43_phy_read(dev, 0x04A0)
-				    & 0xF0FF) | 0x0100);
-
-	if (phy->rev == 1) {
-		b43_phy_write(dev, 0x04A2, (b43_phy_read(dev, 0x04A2)
-					    & 0xFFF0) | 0x0007);
-	}
-
-	b43_phy_write(dev, 0x0488, (b43_phy_read(dev, 0x0488)
-				    & 0xFF00) | 0x001C);
-	b43_phy_write(dev, 0x0488, (b43_phy_read(dev, 0x0488)
-				    & 0xC0FF) | 0x0200);
-	b43_phy_write(dev, 0x0496, (b43_phy_read(dev, 0x0496)
-				    & 0xFF00) | 0x001C);
-	b43_phy_write(dev, 0x0489, (b43_phy_read(dev, 0x0489)
-				    & 0xFF00) | 0x0020);
-	b43_phy_write(dev, 0x0489, (b43_phy_read(dev, 0x0489)
-				    & 0xC0FF) | 0x0200);
-	b43_phy_write(dev, 0x0482, (b43_phy_read(dev, 0x0482)
-				    & 0xFF00) | 0x002E);
-	b43_phy_write(dev, 0x0496, (b43_phy_read(dev, 0x0496)
-				    & 0x00FF) | 0x1A00);
-	b43_phy_write(dev, 0x0481, (b43_phy_read(dev, 0x0481)
-				    & 0xFF00) | 0x0028);
-	b43_phy_write(dev, 0x0481, (b43_phy_read(dev, 0x0481)
-				    & 0x00FF) | 0x2C00);
-
-	if (phy->rev == 1) {
-		b43_phy_write(dev, 0x0430, 0x092B);
-		b43_phy_write(dev, 0x041B, (b43_phy_read(dev, 0x041B)
-					    & 0xFFE1) | 0x0002);
-	} else {
-		b43_phy_write(dev, 0x041B, b43_phy_read(dev, 0x041B)
-			      & 0xFFE1);
-		b43_phy_write(dev, 0x041F, 0x287A);
-		b43_phy_write(dev, 0x0420, (b43_phy_read(dev, 0x0420)
-					    & 0xFFF0) | 0x0004);
-	}
-
-	if (phy->rev >= 6) {
-		b43_phy_write(dev, 0x0422, 0x287A);
-		b43_phy_write(dev, 0x0420, (b43_phy_read(dev, 0x0420)
-					    & 0x0FFF) | 0x3000);
-	}
-
-	b43_phy_write(dev, 0x04A8, (b43_phy_read(dev, 0x04A8)
-				    & 0x8080) | 0x7874);
-	b43_phy_write(dev, 0x048E, 0x1C00);
-
-	offset = 0x0800;
-	if (phy->rev == 1) {
-		offset = 0x5400;
-		b43_phy_write(dev, 0x04AB, (b43_phy_read(dev, 0x04AB)
-					    & 0xF0FF) | 0x0600);
-		b43_phy_write(dev, 0x048B, 0x005E);
-		b43_phy_write(dev, 0x048C, (b43_phy_read(dev, 0x048C)
-					    & 0xFF00) | 0x001E);
-		b43_phy_write(dev, 0x048D, 0x0002);
-	}
-	b43_ofdmtab_write16(dev, offset, 0, 0x00);
-	b43_ofdmtab_write16(dev, offset, 1, 0x07);
-	b43_ofdmtab_write16(dev, offset, 2, 0x10);
-	b43_ofdmtab_write16(dev, offset, 3, 0x1C);
-
-	if (phy->rev >= 6) {
-		b43_phy_write(dev, 0x0426, b43_phy_read(dev, 0x0426)
-			      & 0xFFFC);
-		b43_phy_write(dev, 0x0426, b43_phy_read(dev, 0x0426)
-			      & 0xEFFF);
-	}
-}
-
-static void b43_phy_setupg(struct b43_wldev *dev)
+static void b43_phy_rssiagc(struct b43_wldev *dev, u8 enable)
 {
-	struct ssb_bus *bus = dev->dev->bus;
-	struct b43_phy *phy = &dev->phy;
-	u16 i;
-
-	B43_WARN_ON(phy->type != B43_PHYTYPE_G);
-	if (phy->rev == 1) {
-		b43_phy_write(dev, 0x0406, 0x4F19);
-		b43_phy_write(dev, B43_PHY_G_CRS,
-			      (b43_phy_read(dev, B43_PHY_G_CRS) & 0xFC3F) |
-			      0x0340);
-		b43_phy_write(dev, 0x042C, 0x005A);
-		b43_phy_write(dev, 0x0427, 0x001A);
-
-		for (i = 0; i < B43_TAB_FINEFREQG_SIZE; i++)
-			b43_ofdmtab_write16(dev, 0x5800, i,
-					    b43_tab_finefreqg[i]);
-		for (i = 0; i < B43_TAB_NOISEG1_SIZE; i++)
-			b43_ofdmtab_write16(dev, 0x1800, i, b43_tab_noiseg1[i]);
-		for (i = 0; i < B43_TAB_ROTOR_SIZE; i++)
-			b43_ofdmtab_write16(dev, 0x2000, i, b43_tab_rotor[i]);
-	} else {
-		/* nrssi values are signed 6-bit values. Not sure why we write 0x7654 here... */
-		b43_nrssi_hw_write(dev, 0xBA98, (s16) 0x7654);
-
-		if (phy->rev == 2) {
-			b43_phy_write(dev, 0x04C0, 0x1861);
-			b43_phy_write(dev, 0x04C1, 0x0271);
-		} else if (phy->rev > 2) {
-			b43_phy_write(dev, 0x04C0, 0x0098);
-			b43_phy_write(dev, 0x04C1, 0x0070);
-			b43_phy_write(dev, 0x04C9, 0x0080);
-		}
-		b43_phy_write(dev, 0x042B, b43_phy_read(dev, 0x042B) | 0x800);
-
-		for (i = 0; i < 64; i++)
-			b43_ofdmtab_write16(dev, 0x4000, i, i);
-		for (i = 0; i < B43_TAB_NOISEG2_SIZE; i++)
-			b43_ofdmtab_write16(dev, 0x1800, i, b43_tab_noiseg2[i]);
-	}
-
-	if (phy->rev <= 2)
-		for (i = 0; i < B43_TAB_NOISESCALEG_SIZE; i++)
-			b43_ofdmtab_write16(dev, 0x1400, i,
-					    b43_tab_noisescaleg1[i]);
-	else if ((phy->rev >= 7) && (b43_phy_read(dev, 0x0449) & 0x0200))
-		for (i = 0; i < B43_TAB_NOISESCALEG_SIZE; i++)
-			b43_ofdmtab_write16(dev, 0x1400, i,
-					    b43_tab_noisescaleg3[i]);
-	else
-		for (i = 0; i < B43_TAB_NOISESCALEG_SIZE; i++)
-			b43_ofdmtab_write16(dev, 0x1400, i,
-					    b43_tab_noisescaleg2[i]);
-
-	if (phy->rev == 2)
-		for (i = 0; i < B43_TAB_SIGMASQR_SIZE; i++)
-			b43_ofdmtab_write16(dev, 0x5000, i,
-					    b43_tab_sigmasqr1[i]);
-	else if ((phy->rev > 2) && (phy->rev <= 8))
-		for (i = 0; i < B43_TAB_SIGMASQR_SIZE; i++)
-			b43_ofdmtab_write16(dev, 0x5000, i,
-					    b43_tab_sigmasqr2[i]);
-
-	if (phy->rev == 1) {
-		for (i = 0; i < B43_TAB_RETARD_SIZE; i++)
-			b43_ofdmtab_write32(dev, 0x2400, i, b43_tab_retard[i]);
-		for (i = 4; i < 20; i++)
-			b43_ofdmtab_write16(dev, 0x5400, i, 0x0020);
-		b43_phy_agcsetup(dev);
-
-		if ((bus->boardinfo.vendor == SSB_BOARDVENDOR_BCM) &&
-		    (bus->boardinfo.type == SSB_BOARD_BU4306) &&
-		    (bus->boardinfo.rev == 0x17))
-			return;
-
-		b43_ofdmtab_write16(dev, 0x5001, 0, 0x0002);
-		b43_ofdmtab_write16(dev, 0x5002, 0, 0x0001);
-	} else {
-		for (i = 0; i < 0x20; i++)
-			b43_ofdmtab_write16(dev, 0x1000, i, 0x0820);
-		b43_phy_agcsetup(dev);
-		b43_phy_read(dev, 0x0400);	/* dummy read */
-		b43_phy_write(dev, 0x0403, 0x1000);
-		b43_ofdmtab_write16(dev, 0x3C02, 0, 0x000F);
-		b43_ofdmtab_write16(dev, 0x3C03, 0, 0x0014);
-
-		if ((bus->boardinfo.vendor == SSB_BOARDVENDOR_BCM) &&
-		    (bus->boardinfo.type == SSB_BOARD_BU4306) &&
-		    (bus->boardinfo.rev == 0x17))
-			return;
-
-		b43_ofdmtab_write16(dev, 0x0401, 0, 0x0002);
-		b43_ofdmtab_write16(dev, 0x0402, 0, 0x0001);
-	}
-}
-
-/* Initialize the noisescaletable for APHY */
-static void b43_phy_init_noisescaletbl(struct b43_wldev *dev)
-{
-	struct b43_phy *phy = &dev->phy;
 	int i;
 
-	for (i = 0; i < 12; i++) {
-		if (phy->rev == 2)
-			b43_ofdmtab_write16(dev, 0x1400, i, 0x6767);
+	if (dev->phy.rev < 3) {
+		if (enable)
+			for (i = 0; i < B43_TAB_RSSIAGC1_SIZE; i++) {
+				b43_ofdmtab_write16(dev,
+					B43_OFDMTAB_LNAHPFGAIN1, i, 0xFFF8);
+				b43_ofdmtab_write16(dev,
+					B43_OFDMTAB_WRSSI, i, 0xFFF8);
+			}
 		else
-			b43_ofdmtab_write16(dev, 0x1400, i, 0x2323);
-	}
-	if (phy->rev == 2)
-		b43_ofdmtab_write16(dev, 0x1400, i, 0x6700);
-	else
-		b43_ofdmtab_write16(dev, 0x1400, i, 0x2300);
-	for (i = 0; i < 11; i++) {
-		if (phy->rev == 2)
-			b43_ofdmtab_write16(dev, 0x1400, i, 0x6767);
+			for (i = 0; i < B43_TAB_RSSIAGC1_SIZE; i++) {
+				b43_ofdmtab_write16(dev,
+					B43_OFDMTAB_LNAHPFGAIN1, i, b43_tab_rssiagc1[i]);
+				b43_ofdmtab_write16(dev,
+					B43_OFDMTAB_WRSSI, i, b43_tab_rssiagc1[i]);
+			}
+	} else {
+		if (enable)
+			for (i = 0; i < B43_TAB_RSSIAGC1_SIZE; i++)
+				b43_ofdmtab_write16(dev,
+					B43_OFDMTAB_WRSSI, i, 0x0820);
 		else
-			b43_ofdmtab_write16(dev, 0x1400, i, 0x2323);
+			for (i = 0; i < B43_TAB_RSSIAGC2_SIZE; i++)
+				b43_ofdmtab_write16(dev,
+					B43_OFDMTAB_WRSSI, i, b43_tab_rssiagc2[i]);
 	}
-	if (phy->rev == 2)
-		b43_ofdmtab_write16(dev, 0x1400, i, 0x0067);
-	else
-		b43_ofdmtab_write16(dev, 0x1400, i, 0x0023);
 }
 
-static void b43_phy_setupa(struct b43_wldev *dev)
+static void b43_phy_ww(struct b43_wldev *dev)
 {
-	struct b43_phy *phy = &dev->phy;
-	u16 i;
-
-	B43_WARN_ON(phy->type != B43_PHYTYPE_A);
-	switch (phy->rev) {
-	case 2:
-		b43_phy_write(dev, 0x008E, 0x3800);
-		b43_phy_write(dev, 0x0035, 0x03FF);
-		b43_phy_write(dev, 0x0036, 0x0400);
-
-		b43_ofdmtab_write16(dev, 0x3807, 0, 0x0051);
-
-		b43_phy_write(dev, 0x001C, 0x0FF9);
-		b43_phy_write(dev, 0x0020, b43_phy_read(dev, 0x0020) & 0xFF0F);
-		b43_ofdmtab_write16(dev, 0x3C0C, 0, 0x07BF);
-		b43_radio_write16(dev, 0x0002, 0x07BF);
-
-		b43_phy_write(dev, 0x0024, 0x4680);
-		b43_phy_write(dev, 0x0020, 0x0003);
-		b43_phy_write(dev, 0x001D, 0x0F40);
-		b43_phy_write(dev, 0x001F, 0x1C00);
-
-		b43_phy_write(dev, 0x002A, (b43_phy_read(dev, 0x002A)
-					    & 0x00FF) | 0x0400);
-		b43_phy_write(dev, 0x002B, b43_phy_read(dev, 0x002B)
-			      & 0xFBFF);
-		b43_phy_write(dev, 0x008E, 0x58C1);
-
-		b43_ofdmtab_write16(dev, 0x0803, 0, 0x000F);
-		b43_ofdmtab_write16(dev, 0x0804, 0, 0x001F);
-		b43_ofdmtab_write16(dev, 0x0805, 0, 0x002A);
-		b43_ofdmtab_write16(dev, 0x0805, 0, 0x0030);
-		b43_ofdmtab_write16(dev, 0x0807, 0, 0x003A);
-
-		b43_ofdmtab_write16(dev, 0x0000, 0, 0x0013);
-		b43_ofdmtab_write16(dev, 0x0000, 1, 0x0013);
-		b43_ofdmtab_write16(dev, 0x0000, 2, 0x0013);
-		b43_ofdmtab_write16(dev, 0x0000, 3, 0x0013);
-		b43_ofdmtab_write16(dev, 0x0000, 4, 0x0015);
-		b43_ofdmtab_write16(dev, 0x0000, 5, 0x0015);
-		b43_ofdmtab_write16(dev, 0x0000, 6, 0x0019);
-
-		b43_ofdmtab_write16(dev, 0x0404, 0, 0x0003);
-		b43_ofdmtab_write16(dev, 0x0405, 0, 0x0003);
-		b43_ofdmtab_write16(dev, 0x0406, 0, 0x0007);
-
-		for (i = 0; i < 16; i++)
-			b43_ofdmtab_write16(dev, 0x4000, i, (0x8 + i) & 0x000F);
-
-		b43_ofdmtab_write16(dev, 0x3003, 0, 0x1044);
-		b43_ofdmtab_write16(dev, 0x3004, 0, 0x7201);
-		b43_ofdmtab_write16(dev, 0x3006, 0, 0x0040);
-		b43_ofdmtab_write16(dev, 0x3001, 0,
-				    (b43_ofdmtab_read16(dev, 0x3001, 0) &
-				     0x0010) | 0x0008);
-
-		for (i = 0; i < B43_TAB_FINEFREQA_SIZE; i++)
-			b43_ofdmtab_write16(dev, 0x5800, i,
-					    b43_tab_finefreqa[i]);
-		for (i = 0; i < B43_TAB_NOISEA2_SIZE; i++)
-			b43_ofdmtab_write16(dev, 0x1800, i, b43_tab_noisea2[i]);
-		for (i = 0; i < B43_TAB_ROTOR_SIZE; i++)
-			b43_ofdmtab_write32(dev, 0x2000, i, b43_tab_rotor[i]);
-		b43_phy_init_noisescaletbl(dev);
-		for (i = 0; i < B43_TAB_RETARD_SIZE; i++)
-			b43_ofdmtab_write32(dev, 0x2400, i, b43_tab_retard[i]);
-		break;
-	case 3:
-		for (i = 0; i < 64; i++)
-			b43_ofdmtab_write16(dev, 0x4000, i, i);
-
-		b43_ofdmtab_write16(dev, 0x3807, 0, 0x0051);
-
-		b43_phy_write(dev, 0x001C, 0x0FF9);
-		b43_phy_write(dev, 0x0020, b43_phy_read(dev, 0x0020) & 0xFF0F);
-		b43_radio_write16(dev, 0x0002, 0x07BF);
-
-		b43_phy_write(dev, 0x0024, 0x4680);
-		b43_phy_write(dev, 0x0020, 0x0003);
-		b43_phy_write(dev, 0x001D, 0x0F40);
-		b43_phy_write(dev, 0x001F, 0x1C00);
-		b43_phy_write(dev, 0x002A, (b43_phy_read(dev, 0x002A)
-					    & 0x00FF) | 0x0400);
-
-		b43_ofdmtab_write16(dev, 0x3000, 1,
-				    (b43_ofdmtab_read16(dev, 0x3000, 1)
-				     & 0x0010) | 0x0008);
-		for (i = 0; i < B43_TAB_NOISEA3_SIZE; i++) {
-			b43_ofdmtab_write16(dev, 0x1800, i, b43_tab_noisea3[i]);
-		}
-		b43_phy_init_noisescaletbl(dev);
-		for (i = 0; i < B43_TAB_SIGMASQR_SIZE; i++) {
-			b43_ofdmtab_write16(dev, 0x5000, i,
-					    b43_tab_sigmasqr1[i]);
-		}
-
-		b43_phy_write(dev, 0x0003, 0x1808);
-
-		b43_ofdmtab_write16(dev, 0x0803, 0, 0x000F);
-		b43_ofdmtab_write16(dev, 0x0804, 0, 0x001F);
-		b43_ofdmtab_write16(dev, 0x0805, 0, 0x002A);
-		b43_ofdmtab_write16(dev, 0x0805, 0, 0x0030);
-		b43_ofdmtab_write16(dev, 0x0807, 0, 0x003A);
-
-		b43_ofdmtab_write16(dev, 0x0000, 0, 0x0013);
-		b43_ofdmtab_write16(dev, 0x0001, 0, 0x0013);
-		b43_ofdmtab_write16(dev, 0x0002, 0, 0x0013);
-		b43_ofdmtab_write16(dev, 0x0003, 0, 0x0013);
-		b43_ofdmtab_write16(dev, 0x0004, 0, 0x0015);
-		b43_ofdmtab_write16(dev, 0x0005, 0, 0x0015);
-		b43_ofdmtab_write16(dev, 0x0006, 0, 0x0019);
-
-		b43_ofdmtab_write16(dev, 0x0404, 0, 0x0003);
-		b43_ofdmtab_write16(dev, 0x0405, 0, 0x0003);
-		b43_ofdmtab_write16(dev, 0x0406, 0, 0x0007);
+	u16 b, curr_s, best_s = 0xFFFF;
+	int i;
 
-		b43_ofdmtab_write16(dev, 0x3C02, 0, 0x000F);
-		b43_ofdmtab_write16(dev, 0x3C03, 0, 0x0014);
-		break;
-	default:
-		B43_WARN_ON(1);
+	b43_phy_write(dev, B43_PHY_CRS0,
+		b43_phy_read(dev, B43_PHY_CRS0) & ~B43_PHY_CRS0_EN);
+	b43_phy_write(dev, B43_PHY_OFDM(0x1B),
+		b43_phy_read(dev, B43_PHY_OFDM(0x1B)) | 0x1000);
+	b43_phy_write(dev, B43_PHY_OFDM(0x82),
+		(b43_phy_read(dev, B43_PHY_OFDM(0x82)) & 0xF0FF) | 0x0300);
+	b43_radio_write16(dev, 0x0009,
+		b43_radio_read16(dev, 0x0009) | 0x0080);
+	b43_radio_write16(dev, 0x0012,
+		(b43_radio_read16(dev, 0x0012) & 0xFFFC) | 0x0002);
+	b43_wa_initgains(dev);
+	b43_phy_write(dev, B43_PHY_OFDM(0xBA), 0x3ED5);
+	b = b43_phy_read(dev, B43_PHY_PWRDOWN);
+	b43_phy_write(dev, B43_PHY_PWRDOWN, (b & 0xFFF8) | 0x0005);
+	b43_radio_write16(dev, 0x0004,
+		b43_radio_read16(dev, 0x0004) | 0x0004);
+	for (i = 0x10; i <= 0x20; i++) {
+		b43_radio_write16(dev, 0x0013, i);
+		curr_s = b43_phy_read(dev, B43_PHY_OTABLEQ) & 0x00FF;
+		if (!curr_s) {
+			best_s = 0x0000;
+			break;
+		} else if (curr_s >= 0x0080)
+			curr_s = 0x0100 - curr_s;
+		if (curr_s < best_s)
+			best_s = curr_s;
 	}
+	b43_phy_write(dev, B43_PHY_PWRDOWN, b);
+	b43_radio_write16(dev, 0x0004,
+		b43_radio_read16(dev, 0x0004) & 0xFFFB);
+	b43_radio_write16(dev, 0x0013, best_s);
+	b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC1_R1, 0, 0xFFEC);
+	b43_phy_write(dev, B43_PHY_OFDM(0xB7), 0x1E80);
+	b43_phy_write(dev, B43_PHY_OFDM(0xB6), 0x1C00);
+	b43_phy_write(dev, B43_PHY_OFDM(0xB5), 0x0EC0);
+	b43_phy_write(dev, B43_PHY_OFDM(0xB2), 0x00C0);
+	b43_phy_write(dev, B43_PHY_OFDM(0xB9), 0x1FFF);
+	b43_phy_write(dev, B43_PHY_OFDM(0xBB),
+		(b43_phy_read(dev, B43_PHY_OFDM(0xBB)) & 0xF000) | 0x0053);
+	b43_phy_write(dev, B43_PHY_OFDM61,
+		(b43_phy_read(dev, B43_PHY_OFDM61 & 0xFE1F)) | 0x0120);
+	b43_phy_write(dev, B43_PHY_OFDM(0x13),
+		(b43_phy_read(dev, B43_PHY_OFDM(0x13)) & 0x0FFF) | 0x3000);
+	b43_phy_write(dev, B43_PHY_OFDM(0x14),
+		(b43_phy_read(dev, B43_PHY_OFDM(0x14)) & 0x0FFF) | 0x3000);
+	b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC1, 6, 0x0017);
+	for (i = 0; i < 6; i++)
+		b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC1, i, 0x000F);
+	b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC1, 0x0D, 0x000E);
+	b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC1, 0x0E, 0x0011);
+	b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC1, 0x0F, 0x0013);
+	b43_phy_write(dev, B43_PHY_OFDM(0x33), 0x5030);
+	b43_phy_write(dev, B43_PHY_CRS0,
+		b43_phy_read(dev, B43_PHY_CRS0) | B43_PHY_CRS0_EN);
 }
 
 /* Initialize APHY. This is also called for the GPHY in some cases. */
@@ -1130,64 +881,54 @@ static void b43_phy_inita(struct b43_wldev *dev)
 {
 	struct ssb_bus *bus = dev->dev->bus;
 	struct b43_phy *phy = &dev->phy;
-	u16 tval;
 
 	might_sleep();
 
-	if (phy->type == B43_PHYTYPE_A) {
-		b43_phy_setupa(dev);
-	} else {
-		b43_phy_setupg(dev);
-		if (phy->gmode &&
-		    (dev->dev->bus->sprom.r1.boardflags_lo & B43_BFL_PACTRL))
-			b43_phy_write(dev, 0x046E, 0x03CF);
-		return;
+	if (phy->rev >= 6) {
+		if (phy->type == B43_PHYTYPE_A)
+			b43_phy_write(dev, B43_PHY_OFDM(0x1B),
+				b43_phy_read(dev, B43_PHY_OFDM(0x1B)) & ~0x1000);
+		if (b43_phy_read(dev, B43_PHY_ENCORE) & B43_PHY_ENCORE_EN)
+			b43_phy_write(dev, B43_PHY_ENCORE,
+				b43_phy_read(dev, B43_PHY_ENCORE) | 0x0010);
+		else
+			b43_phy_write(dev, B43_PHY_ENCORE,
+				b43_phy_read(dev, B43_PHY_ENCORE) & ~0x1010);
 	}
 
-	b43_phy_write(dev, B43_PHY_A_CRS,
-		      (b43_phy_read(dev, B43_PHY_A_CRS) & 0xF83C) | 0x0340);
-	b43_phy_write(dev, 0x0034, 0x0001);
+	b43_wa_all(dev);
 
-	//TODO: RSSI AGC
-	b43_phy_write(dev, B43_PHY_A_CRS,
-		      b43_phy_read(dev, B43_PHY_A_CRS) | (1 << 14));
-	b43_radio_init2060(dev);
+	if (phy->type == B43_PHYTYPE_A) {
+		if (phy->gmode && (phy->rev < 3))
+			b43_phy_write(dev, 0x0034,
+				b43_phy_read(dev, 0x0034) | 0x0001);
+		b43_phy_rssiagc(dev, 0);
 
-	if ((bus->boardinfo.vendor == SSB_BOARDVENDOR_BCM) &&
-	    ((bus->boardinfo.type == SSB_BOARD_BU4306) ||
-	     (bus->boardinfo.type == SSB_BOARD_BU4309))) {
-		if (phy->lofcal == 0xFFFF) {
-			//TODO: LOF Cal
-			b43_radio_set_tx_iq(dev);
-		} else
-			b43_radio_write16(dev, 0x001E, phy->lofcal);
-	}
+		b43_phy_write(dev, B43_PHY_CRS0,
+			b43_phy_read(dev, B43_PHY_CRS0) | B43_PHY_CRS0_EN);
 
-	b43_phy_write(dev, 0x007A, 0xF111);
+		b43_radio_init2060(dev);
 
-	if (phy->cur_idle_tssi == 0) {
-		b43_radio_write16(dev, 0x0019, 0x0000);
-		b43_radio_write16(dev, 0x0017, 0x0020);
-
-		tval = b43_ofdmtab_read16(dev, 0x3001, 0);
-		if (phy->rev == 1) {
-			b43_ofdmtab_write16(dev, 0x3001, 0,
-					    (b43_ofdmtab_read16(dev, 0x3001, 0)
-					     & 0xFF87)
-					    | 0x0058);
-		} else {
-			b43_ofdmtab_write16(dev, 0x3001, 0,
-					    (b43_ofdmtab_read16(dev, 0x3001, 0)
-					     & 0xFFC3)
-					    | 0x002C);
+		if ((bus->boardinfo.vendor == SSB_BOARDVENDOR_BCM) &&
+		    ((bus->boardinfo.type == SSB_BOARD_BU4306) ||
+		     (bus->boardinfo.type == SSB_BOARD_BU4309))) {
+			; //TODO: A PHY LO
 		}
-		b43_dummy_transmission(dev);
-		phy->cur_idle_tssi = b43_phy_read(dev, B43_PHY_A_PCTL);
-		b43_ofdmtab_write16(dev, 0x3001, 0, tval);
 
-		b43_radio_set_txpower_a(dev, 0x0018);
+		if (phy->rev >= 3)
+			b43_phy_ww(dev);
+
+		hardware_pctl_init_aphy(dev);
+
+		//TODO: radar detection
+	}
+
+	if ((phy->type == B43_PHYTYPE_G) &&
+	    (dev->dev->bus->sprom.boardflags_lo & B43_BFL_PACTRL)) {
+		b43_phy_write(dev, B43_PHY_OFDM(0x6E),
+				  (b43_phy_read(dev, B43_PHY_OFDM(0x6E))
+				   & 0xE000) | 0x3CF);
 	}
-	b43_shm_clear_tssi(dev);
 }
 
 static void b43_phy_initb2(struct b43_wldev *dev)
@@ -1286,7 +1027,7 @@ static void b43_phy_initb4(struct b43_wldev *dev)
 	if (phy->radio_ver == 0x2050)
 		b43_phy_write(dev, 0x002A, 0x88C2);
 	b43_set_txpower_g(dev, &phy->bbatt, &phy->rfatt, phy->tx_control);
-	if (dev->dev->bus->sprom.r1.boardflags_lo & B43_BFL_RSSI) {
+	if (dev->dev->bus->sprom.boardflags_lo & B43_BFL_RSSI) {
 		b43_calc_nrssi_slope(dev);
 		b43_calc_nrssi_threshold(dev);
 	}
@@ -1433,7 +1174,7 @@ static void b43_phy_initb6(struct b43_wldev *dev)
 		b43_radio_write16(dev, 0x5A, 0x88);
 		b43_radio_write16(dev, 0x5B, 0x6B);
 		b43_radio_write16(dev, 0x5C, 0x0F);
-		if (dev->dev->bus->sprom.r1.boardflags_lo & B43_BFL_ALTIQ) {
+		if (dev->dev->bus->sprom.boardflags_lo & B43_BFL_ALTIQ) {
 			b43_radio_write16(dev, 0x5D, 0xFA);
 			b43_radio_write16(dev, 0x5E, 0xD8);
 		} else {
@@ -1525,7 +1266,7 @@ static void b43_phy_initb6(struct b43_wldev *dev)
 		b43_phy_write(dev, 0x0062, 0x0007);
 		b43_radio_init2050(dev);
 		b43_lo_g_measure(dev);
-		if (dev->dev->bus->sprom.r1.boardflags_lo & B43_BFL_RSSI) {
+		if (dev->dev->bus->sprom.boardflags_lo & B43_BFL_RSSI) {
 			b43_calc_nrssi_slope(dev);
 			b43_calc_nrssi_threshold(dev);
 		}
@@ -1552,14 +1293,14 @@ static void b43_calc_loopback_gain(struct b43_wldev *dev)
 		backup_phy[4] = b43_phy_read(dev, B43_PHY_ANALOGOVER);
 		backup_phy[5] = b43_phy_read(dev, B43_PHY_ANALOGOVERVAL);
 	}
-	backup_phy[6] = b43_phy_read(dev, B43_PHY_BASE(0x5A));
-	backup_phy[7] = b43_phy_read(dev, B43_PHY_BASE(0x59));
-	backup_phy[8] = b43_phy_read(dev, B43_PHY_BASE(0x58));
-	backup_phy[9] = b43_phy_read(dev, B43_PHY_BASE(0x0A));
-	backup_phy[10] = b43_phy_read(dev, B43_PHY_BASE(0x03));
+	backup_phy[6] = b43_phy_read(dev, B43_PHY_CCK(0x5A));
+	backup_phy[7] = b43_phy_read(dev, B43_PHY_CCK(0x59));
+	backup_phy[8] = b43_phy_read(dev, B43_PHY_CCK(0x58));
+	backup_phy[9] = b43_phy_read(dev, B43_PHY_CCK(0x0A));
+	backup_phy[10] = b43_phy_read(dev, B43_PHY_CCK(0x03));
 	backup_phy[11] = b43_phy_read(dev, B43_PHY_LO_MASK);
 	backup_phy[12] = b43_phy_read(dev, B43_PHY_LO_CTL);
-	backup_phy[13] = b43_phy_read(dev, B43_PHY_BASE(0x2B));
+	backup_phy[13] = b43_phy_read(dev, B43_PHY_CCK(0x2B));
 	backup_phy[14] = b43_phy_read(dev, B43_PHY_PGACTL);
 	backup_phy[15] = b43_phy_read(dev, B43_PHY_LO_LEAKAGE);
 	backup_bband = phy->bbatt.att;
@@ -1601,12 +1342,12 @@ static void b43_calc_loopback_gain(struct b43_wldev *dev)
 		      (b43_phy_read(dev, B43_PHY_RFOVERVAL)
 		       & 0xFFCF) | 0x10);
 
-	b43_phy_write(dev, B43_PHY_BASE(0x5A), 0x0780);
-	b43_phy_write(dev, B43_PHY_BASE(0x59), 0xC810);
-	b43_phy_write(dev, B43_PHY_BASE(0x58), 0x000D);
+	b43_phy_write(dev, B43_PHY_CCK(0x5A), 0x0780);
+	b43_phy_write(dev, B43_PHY_CCK(0x59), 0xC810);
+	b43_phy_write(dev, B43_PHY_CCK(0x58), 0x000D);
 
-	b43_phy_write(dev, B43_PHY_BASE(0x0A),
-		      b43_phy_read(dev, B43_PHY_BASE(0x0A)) | 0x2000);
+	b43_phy_write(dev, B43_PHY_CCK(0x0A),
+		      b43_phy_read(dev, B43_PHY_CCK(0x0A)) | 0x2000);
 	if (phy->rev != 1) {	/* Not in specs, but needed to prevent PPC machine check */
 		b43_phy_write(dev, B43_PHY_ANALOGOVER,
 			      b43_phy_read(dev, B43_PHY_ANALOGOVER) | 0x0004);
@@ -1614,8 +1355,8 @@ static void b43_calc_loopback_gain(struct b43_wldev *dev)
 			      b43_phy_read(dev,
 					   B43_PHY_ANALOGOVERVAL) & 0xFFFB);
 	}
-	b43_phy_write(dev, B43_PHY_BASE(0x03),
-		      (b43_phy_read(dev, B43_PHY_BASE(0x03))
+	b43_phy_write(dev, B43_PHY_CCK(0x03),
+		      (b43_phy_read(dev, B43_PHY_CCK(0x03))
 		       & 0xFF9F) | 0x40);
 
 	if (phy->radio_rev == 8) {
@@ -1633,11 +1374,11 @@ static void b43_calc_loopback_gain(struct b43_wldev *dev)
 		b43_phy_write(dev, B43_PHY_LO_MASK, 0x8020);
 	b43_phy_write(dev, B43_PHY_LO_CTL, 0);
 
-	b43_phy_write(dev, B43_PHY_BASE(0x2B),
-		      (b43_phy_read(dev, B43_PHY_BASE(0x2B))
+	b43_phy_write(dev, B43_PHY_CCK(0x2B),
+		      (b43_phy_read(dev, B43_PHY_CCK(0x2B))
 		       & 0xFFC0) | 0x01);
-	b43_phy_write(dev, B43_PHY_BASE(0x2B),
-		      (b43_phy_read(dev, B43_PHY_BASE(0x2B))
+	b43_phy_write(dev, B43_PHY_CCK(0x2B),
+		      (b43_phy_read(dev, B43_PHY_CCK(0x2B))
 		       & 0xC0FF) | 0x800);
 
 	b43_phy_write(dev, B43_PHY_RFOVER,
@@ -1645,7 +1386,7 @@ static void b43_calc_loopback_gain(struct b43_wldev *dev)
 	b43_phy_write(dev, B43_PHY_RFOVERVAL,
 		      b43_phy_read(dev, B43_PHY_RFOVERVAL) & 0xCFFF);
 
-	if (dev->dev->bus->sprom.r1.boardflags_lo & B43_BFL_EXTLNA) {
+	if (dev->dev->bus->sprom.boardflags_lo & B43_BFL_EXTLNA) {
 		if (phy->rev >= 7) {
 			b43_phy_write(dev, B43_PHY_RFOVER,
 				      b43_phy_read(dev, B43_PHY_RFOVER)
@@ -1708,14 +1449,14 @@ static void b43_calc_loopback_gain(struct b43_wldev *dev)
 		b43_phy_write(dev, B43_PHY_ANALOGOVER, backup_phy[4]);
 		b43_phy_write(dev, B43_PHY_ANALOGOVERVAL, backup_phy[5]);
 	}
-	b43_phy_write(dev, B43_PHY_BASE(0x5A), backup_phy[6]);
-	b43_phy_write(dev, B43_PHY_BASE(0x59), backup_phy[7]);
-	b43_phy_write(dev, B43_PHY_BASE(0x58), backup_phy[8]);
-	b43_phy_write(dev, B43_PHY_BASE(0x0A), backup_phy[9]);
-	b43_phy_write(dev, B43_PHY_BASE(0x03), backup_phy[10]);
+	b43_phy_write(dev, B43_PHY_CCK(0x5A), backup_phy[6]);
+	b43_phy_write(dev, B43_PHY_CCK(0x59), backup_phy[7]);
+	b43_phy_write(dev, B43_PHY_CCK(0x58), backup_phy[8]);
+	b43_phy_write(dev, B43_PHY_CCK(0x0A), backup_phy[9]);
+	b43_phy_write(dev, B43_PHY_CCK(0x03), backup_phy[10]);
 	b43_phy_write(dev, B43_PHY_LO_MASK, backup_phy[11]);
 	b43_phy_write(dev, B43_PHY_LO_CTL, backup_phy[12]);
-	b43_phy_write(dev, B43_PHY_BASE(0x2B), backup_phy[13]);
+	b43_phy_write(dev, B43_PHY_CCK(0x2B), backup_phy[13]);
 	b43_phy_write(dev, B43_PHY_PGACTL, backup_phy[14]);
 
 	b43_phy_set_baseband_attenuation(dev, backup_bband);
@@ -1807,26 +1548,26 @@ static void b43_phy_initg(struct b43_wldev *dev)
 					  | phy->lo_control->tx_bias);
 		}
 		if (phy->rev >= 6) {
-			b43_phy_write(dev, B43_PHY_BASE(0x36),
-				      (b43_phy_read(dev, B43_PHY_BASE(0x36))
+			b43_phy_write(dev, B43_PHY_CCK(0x36),
+				      (b43_phy_read(dev, B43_PHY_CCK(0x36))
 				       & 0x0FFF) | (phy->lo_control->
 						    tx_bias << 12));
 		}
-		if (dev->dev->bus->sprom.r1.boardflags_lo & B43_BFL_PACTRL)
-			b43_phy_write(dev, B43_PHY_BASE(0x2E), 0x8075);
+		if (dev->dev->bus->sprom.boardflags_lo & B43_BFL_PACTRL)
+			b43_phy_write(dev, B43_PHY_CCK(0x2E), 0x8075);
 		else
-			b43_phy_write(dev, B43_PHY_BASE(0x2E), 0x807F);
+			b43_phy_write(dev, B43_PHY_CCK(0x2E), 0x807F);
 		if (phy->rev < 2)
-			b43_phy_write(dev, B43_PHY_BASE(0x2F), 0x101);
+			b43_phy_write(dev, B43_PHY_CCK(0x2F), 0x101);
 		else
-			b43_phy_write(dev, B43_PHY_BASE(0x2F), 0x202);
+			b43_phy_write(dev, B43_PHY_CCK(0x2F), 0x202);
 	}
 	if (phy->gmode || phy->rev >= 2) {
 		b43_lo_g_adjust(dev);
 		b43_phy_write(dev, B43_PHY_LO_MASK, 0x8078);
 	}
 
-	if (!(dev->dev->bus->sprom.r1.boardflags_lo & B43_BFL_RSSI)) {
+	if (!(dev->dev->bus->sprom.boardflags_lo & B43_BFL_RSSI)) {
 		/* The specs state to update the NRSSI LT with
 		 * the value 0x7FFFFFFF here. I think that is some weird
 		 * compiler optimization in the original driver.
@@ -1995,7 +1736,6 @@ void b43_phy_xmitpower(struct b43_wldev *dev)
 			int rfatt_delta, bbatt_delta;
 			int rfatt, bbatt;
 			u8 tx_control;
-			unsigned long phylock_flags;
 
 			tmp = b43_shm_read16(dev, B43_SHM_SHARED, 0x0058);
 			v0 = (s8) (tmp & 0x00FF);
@@ -2036,16 +1776,15 @@ void b43_phy_xmitpower(struct b43_wldev *dev)
 			estimated_pwr =
 			    b43_phy_estimate_power_out(dev, average);
 
-			max_pwr = dev->dev->bus->sprom.r1.maxpwr_bg;
-			if ((dev->dev->bus->sprom.r1.
-			     boardflags_lo & B43_BFL_PACTRL)
-			    && (phy->type == B43_PHYTYPE_G))
+			max_pwr = dev->dev->bus->sprom.maxpwr_bg;
+			if ((dev->dev->bus->sprom.boardflags_lo
+			    & B43_BFL_PACTRL) && (phy->type == B43_PHYTYPE_G))
 				max_pwr -= 0x3;
 			if (unlikely(max_pwr <= 0)) {
 				b43warn(dev->wl,
 					"Invalid max-TX-power value in SPROM.\n");
 				max_pwr = 60;	/* fake it */
-				dev->dev->bus->sprom.r1.maxpwr_bg = max_pwr;
+				dev->dev->bus->sprom.maxpwr_bg = max_pwr;
 			}
 
 			/*TODO:
@@ -2103,7 +1842,7 @@ void b43_phy_xmitpower(struct b43_wldev *dev)
 						    B43_TXCTL_TXMIX;
 						rfatt += 2;
 						bbatt += 2;
-					} else if (dev->dev->bus->sprom.r1.
+					} else if (dev->dev->bus->sprom.
 						   boardflags_lo &
 						   B43_BFL_PACTRL) {
 						bbatt += 4 * (rfatt - 2);
@@ -2127,15 +1866,18 @@ void b43_phy_xmitpower(struct b43_wldev *dev)
 			phy->bbatt.att = bbatt;
 
 			/* Adjust the hardware */
-			b43_phy_lock(dev, phylock_flags);
+			b43_phy_lock(dev);
 			b43_radio_lock(dev);
 			b43_set_txpower_g(dev, &phy->bbatt, &phy->rfatt,
 					  phy->tx_control);
 			b43_lo_g_ctl_mark_cur_used(dev);
 			b43_radio_unlock(dev);
-			b43_phy_unlock(dev, phylock_flags);
+			b43_phy_unlock(dev);
 			break;
 		}
+	case B43_PHYTYPE_N:
+		b43_nphy_xmitpower(dev);
+		break;
 	default:
 		B43_WARN_ON(1);
 	}
@@ -2179,13 +1921,13 @@ int b43_phy_init_tssi2dbm_table(struct b43_wldev *dev)
 	s8 *dyn_tssi2dbm;
 
 	if (phy->type == B43_PHYTYPE_A) {
-		pab0 = (s16) (dev->dev->bus->sprom.r1.pa1b0);
-		pab1 = (s16) (dev->dev->bus->sprom.r1.pa1b1);
-		pab2 = (s16) (dev->dev->bus->sprom.r1.pa1b2);
+		pab0 = (s16) (dev->dev->bus->sprom.pa1b0);
+		pab1 = (s16) (dev->dev->bus->sprom.pa1b1);
+		pab2 = (s16) (dev->dev->bus->sprom.pa1b2);
 	} else {
-		pab0 = (s16) (dev->dev->bus->sprom.r1.pa0b0);
-		pab1 = (s16) (dev->dev->bus->sprom.r1.pa0b1);
-		pab2 = (s16) (dev->dev->bus->sprom.r1.pa0b2);
+		pab0 = (s16) (dev->dev->bus->sprom.pa0b0);
+		pab1 = (s16) (dev->dev->bus->sprom.pa0b1);
+		pab2 = (s16) (dev->dev->bus->sprom.pa0b2);
 	}
 
 	if ((dev->dev->bus->chip_id == 0x4301) && (phy->radio_ver != 0x2050)) {
@@ -2198,23 +1940,23 @@ int b43_phy_init_tssi2dbm_table(struct b43_wldev *dev)
 	    pab0 != -1 && pab1 != -1 && pab2 != -1) {
 		/* The pabX values are set in SPROM. Use them. */
 		if (phy->type == B43_PHYTYPE_A) {
-			if ((s8) dev->dev->bus->sprom.r1.itssi_a != 0 &&
-			    (s8) dev->dev->bus->sprom.r1.itssi_a != -1)
+			if ((s8) dev->dev->bus->sprom.itssi_a != 0 &&
+			    (s8) dev->dev->bus->sprom.itssi_a != -1)
 				phy->tgt_idle_tssi =
-				    (s8) (dev->dev->bus->sprom.r1.itssi_a);
+				    (s8) (dev->dev->bus->sprom.itssi_a);
 			else
 				phy->tgt_idle_tssi = 62;
 		} else {
-			if ((s8) dev->dev->bus->sprom.r1.itssi_bg != 0 &&
-			    (s8) dev->dev->bus->sprom.r1.itssi_bg != -1)
+			if ((s8) dev->dev->bus->sprom.itssi_bg != 0 &&
+			    (s8) dev->dev->bus->sprom.itssi_bg != -1)
 				phy->tgt_idle_tssi =
-				    (s8) (dev->dev->bus->sprom.r1.itssi_bg);
+				    (s8) (dev->dev->bus->sprom.itssi_bg);
 			else
 				phy->tgt_idle_tssi = 62;
 		}
 		dyn_tssi2dbm = kmalloc(64, GFP_KERNEL);
 		if (dyn_tssi2dbm == NULL) {
-			b43err(dev->wl, "Could not allocate memory"
+			b43err(dev->wl, "Could not allocate memory "
 			       "for tssi2dbm table\n");
 			return -ENOMEM;
 		}
@@ -2255,41 +1997,44 @@ int b43_phy_init_tssi2dbm_table(struct b43_wldev *dev)
 int b43_phy_init(struct b43_wldev *dev)
 {
 	struct b43_phy *phy = &dev->phy;
-	int err = -ENODEV;
+	bool unsupported = 0;
+	int err = 0;
 
 	switch (phy->type) {
 	case B43_PHYTYPE_A:
-		if (phy->rev == 2 || phy->rev == 3) {
+		if (phy->rev == 2 || phy->rev == 3)
 			b43_phy_inita(dev);
-			err = 0;
-		}
+		else
+			unsupported = 1;
 		break;
 	case B43_PHYTYPE_B:
 		switch (phy->rev) {
 		case 2:
 			b43_phy_initb2(dev);
-			err = 0;
 			break;
 		case 4:
 			b43_phy_initb4(dev);
-			err = 0;
 			break;
 		case 5:
 			b43_phy_initb5(dev);
-			err = 0;
 			break;
 		case 6:
 			b43_phy_initb6(dev);
-			err = 0;
 			break;
+		default:
+			unsupported = 1;
 		}
 		break;
 	case B43_PHYTYPE_G:
 		b43_phy_initg(dev);
-		err = 0;
 		break;
+	case B43_PHYTYPE_N:
+		err = b43_phy_initn(dev);
+		break;
+	default:
+		unsupported = 1;
 	}
-	if (err)
+	if (unsupported)
 		b43err(dev->wl, "Unknown PHYTYPE found\n");
 
 	return err;
@@ -2392,6 +2137,9 @@ void b43_set_rx_antenna(struct b43_wldev *dev, int antenna)
 		    << B43_PHY_BBANDCFG_RXANT_SHIFT;
 		b43_phy_write(dev, B43_PHY_CCKBBANDCFG, tmp);
 		break;
+	case B43_PHYTYPE_N:
+		b43_nphy_set_rxantenna(dev, antenna);
+		break;
 	default:
 		B43_WARN_ON(1);
 	}
@@ -2421,6 +2169,7 @@ void b43_radio_lock(struct b43_wldev *dev)
 	u32 macctl;
 
 	macctl = b43_read32(dev, B43_MMIO_MACCTL);
+	B43_WARN_ON(macctl & B43_MACCTL_RADIOLOCK);
 	macctl |= B43_MACCTL_RADIOLOCK;
 	b43_write32(dev, B43_MMIO_MACCTL, macctl);
 	/* Commit the write and wait for the device
@@ -2437,6 +2186,7 @@ void b43_radio_unlock(struct b43_wldev *dev)
 	b43_read16(dev, B43_MMIO_PHY_VER);
 	/* unlock */
 	macctl = b43_read32(dev, B43_MMIO_MACCTL);
+	B43_WARN_ON(!(macctl & B43_MACCTL_RADIOLOCK));
 	macctl &= ~B43_MACCTL_RADIOLOCK;
 	b43_write32(dev, B43_MMIO_MACCTL, macctl);
 }
@@ -2445,9 +2195,12 @@ u16 b43_radio_read16(struct b43_wldev *dev, u16 offset)
 {
 	struct b43_phy *phy = &dev->phy;
 
+	/* Offset 1 is a 32-bit register. */
+	B43_WARN_ON(offset == 1);
+
 	switch (phy->type) {
 	case B43_PHYTYPE_A:
-		offset |= 0x0040;
+		offset |= 0x40;
 		break;
 	case B43_PHYTYPE_B:
 		if (phy->radio_ver == 0x2053) {
@@ -2463,6 +2216,14 @@ u16 b43_radio_read16(struct b43_wldev *dev, u16 offset)
 	case B43_PHYTYPE_G:
 		offset |= 0x80;
 		break;
+	case B43_PHYTYPE_N:
+		offset |= 0x100;
+		break;
+	case B43_PHYTYPE_LP:
+		/* No adjustment required. */
+		break;
+	default:
+		B43_WARN_ON(1);
 	}
 
 	b43_write16(dev, B43_MMIO_RADIO_CONTROL, offset);
@@ -2471,11 +2232,31 @@ u16 b43_radio_read16(struct b43_wldev *dev, u16 offset)
 
 void b43_radio_write16(struct b43_wldev *dev, u16 offset, u16 val)
 {
+	/* Offset 1 is a 32-bit register. */
+	B43_WARN_ON(offset == 1);
+
 	b43_write16(dev, B43_MMIO_RADIO_CONTROL, offset);
-	mmiowb();
 	b43_write16(dev, B43_MMIO_RADIO_DATA_LOW, val);
 }
 
+void b43_radio_mask(struct b43_wldev *dev, u16 offset, u16 mask)
+{
+	b43_radio_write16(dev, offset,
+			  b43_radio_read16(dev, offset) & mask);
+}
+
+void b43_radio_set(struct b43_wldev *dev, u16 offset, u16 set)
+{
+	b43_radio_write16(dev, offset,
+			  b43_radio_read16(dev, offset) | set);
+}
+
+void b43_radio_maskset(struct b43_wldev *dev, u16 offset, u16 mask, u16 set)
+{
+	b43_radio_write16(dev, offset,
+			  (b43_radio_read16(dev, offset) & mask) | set);
+}
+
 static void b43_set_all_gains(struct b43_wldev *dev,
 			      s16 first, s16 second, s16 third)
 {
@@ -2605,12 +2386,11 @@ u8 b43_radio_aci_scan(struct b43_wldev * dev)
 	u8 ret[13];
 	unsigned int channel = phy->channel;
 	unsigned int i, j, start, end;
-	unsigned long phylock_flags;
 
 	if (!((phy->type == B43_PHYTYPE_G) && (phy->rev > 0)))
 		return 0;
 
-	b43_phy_lock(dev, phylock_flags);
+	b43_phy_lock(dev);
 	b43_radio_lock(dev);
 	b43_phy_write(dev, 0x0802, b43_phy_read(dev, 0x0802) & 0xFFFC);
 	b43_phy_write(dev, B43_PHY_G_CRS,
@@ -2639,7 +2419,7 @@ u8 b43_radio_aci_scan(struct b43_wldev * dev)
 			ret[j] = 1;
 	}
 	b43_radio_unlock(dev);
-	b43_phy_unlock(dev, phylock_flags);
+	b43_phy_unlock(dev);
 
 	return ret[channel - 1];
 }
@@ -3114,7 +2894,7 @@ void b43_calc_nrssi_threshold(struct b43_wldev *dev)
 			if (phy->radio_ver != 0x2050)
 				return;
 			if (!
-			    (dev->dev->bus->sprom.r1.
+			    (dev->dev->bus->sprom.
 			     boardflags_lo & B43_BFL_RSSI))
 				return;
 
@@ -3145,7 +2925,7 @@ void b43_calc_nrssi_threshold(struct b43_wldev *dev)
 		}
 	case B43_PHYTYPE_G:
 		if (!phy->gmode ||
-		    !(dev->dev->bus->sprom.r1.boardflags_lo & B43_BFL_RSSI)) {
+		    !(dev->dev->bus->sprom.boardflags_lo & B43_BFL_RSSI)) {
 			tmp16 = b43_nrssi_hw_read(dev, 0x20);
 			if (tmp16 >= 0x20)
 				tmp16 -= 0x40;
@@ -3667,7 +3447,7 @@ static u16 radio2050_rfover_val(struct b43_wldev *dev,
 		}
 
 		if ((phy->rev < 7) ||
-		    !(sprom->r1.boardflags_lo & B43_BFL_EXTLNA)) {
+		    !(sprom->boardflags_lo & B43_BFL_EXTLNA)) {
 			if (phy_register == B43_PHY_RFOVER) {
 				return 0x1B3;
 			} else if (phy_register == B43_PHY_RFOVERVAL) {
@@ -3707,7 +3487,7 @@ static u16 radio2050_rfover_val(struct b43_wldev *dev,
 		}
 	} else {
 		if ((phy->rev < 7) ||
-		    !(sprom->r1.boardflags_lo & B43_BFL_EXTLNA)) {
+		    !(sprom->boardflags_lo & B43_BFL_EXTLNA)) {
 			if (phy_register == B43_PHY_RFOVER) {
 				return 0x1B3;
 			} else if (phy_register == B43_PHY_RFOVERVAL) {
@@ -3757,10 +3537,10 @@ struct init2050_saved_values {
 	u16 radio_52;
 	/* PHY registers */
 	u16 phy_pgactl;
-	u16 phy_base_5A;
-	u16 phy_base_59;
-	u16 phy_base_58;
-	u16 phy_base_30;
+	u16 phy_cck_5A;
+	u16 phy_cck_59;
+	u16 phy_cck_58;
+	u16 phy_cck_30;
 	u16 phy_rfover;
 	u16 phy_rfoverval;
 	u16 phy_analogover;
@@ -3788,15 +3568,15 @@ u16 b43_radio_init2050(struct b43_wldev *dev)
 	sav.radio_51 = b43_radio_read16(dev, 0x51);
 	sav.radio_52 = b43_radio_read16(dev, 0x52);
 	sav.phy_pgactl = b43_phy_read(dev, B43_PHY_PGACTL);
-	sav.phy_base_5A = b43_phy_read(dev, B43_PHY_BASE(0x5A));
-	sav.phy_base_59 = b43_phy_read(dev, B43_PHY_BASE(0x59));
-	sav.phy_base_58 = b43_phy_read(dev, B43_PHY_BASE(0x58));
+	sav.phy_cck_5A = b43_phy_read(dev, B43_PHY_CCK(0x5A));
+	sav.phy_cck_59 = b43_phy_read(dev, B43_PHY_CCK(0x59));
+	sav.phy_cck_58 = b43_phy_read(dev, B43_PHY_CCK(0x58));
 
 	if (phy->type == B43_PHYTYPE_B) {
-		sav.phy_base_30 = b43_phy_read(dev, B43_PHY_BASE(0x30));
+		sav.phy_cck_30 = b43_phy_read(dev, B43_PHY_CCK(0x30));
 		sav.reg_3EC = b43_read16(dev, 0x3EC);
 
-		b43_phy_write(dev, B43_PHY_BASE(0x30), 0xFF);
+		b43_phy_write(dev, B43_PHY_CCK(0x30), 0xFF);
 		b43_write16(dev, 0x3EC, 0x3F3F);
 	} else if (phy->gmode || phy->rev >= 2) {
 		sav.phy_rfover = b43_phy_read(dev, B43_PHY_RFOVER);
@@ -3847,8 +3627,8 @@ u16 b43_radio_init2050(struct b43_wldev *dev)
 		b43_write16(dev, 0x03E6, 0x0122);
 	} else {
 		if (phy->analog >= 2) {
-			b43_phy_write(dev, B43_PHY_BASE(0x03),
-				      (b43_phy_read(dev, B43_PHY_BASE(0x03))
+			b43_phy_write(dev, B43_PHY_CCK(0x03),
+				      (b43_phy_read(dev, B43_PHY_CCK(0x03))
 				       & 0xFFBF) | 0x40);
 		}
 		b43_write16(dev, B43_MMIO_CHANNEL_EXT,
@@ -3865,7 +3645,7 @@ u16 b43_radio_init2050(struct b43_wldev *dev)
 						   LPD(0, 1, 1)));
 	}
 	b43_phy_write(dev, B43_PHY_PGACTL, 0xBFAF);
-	b43_phy_write(dev, B43_PHY_BASE(0x2B), 0x1403);
+	b43_phy_write(dev, B43_PHY_CCK(0x2B), 0x1403);
 	if (phy->gmode || phy->rev >= 2) {
 		b43_phy_write(dev, B43_PHY_RFOVERVAL,
 			      radio2050_rfover_val(dev, B43_PHY_RFOVERVAL,
@@ -3881,12 +3661,12 @@ u16 b43_radio_init2050(struct b43_wldev *dev)
 		b43_radio_write16(dev, 0x43, (b43_radio_read16(dev, 0x43)
 					      & 0xFFF0) | 0x0009);
 	}
-	b43_phy_write(dev, B43_PHY_BASE(0x58), 0);
+	b43_phy_write(dev, B43_PHY_CCK(0x58), 0);
 
 	for (i = 0; i < 16; i++) {
-		b43_phy_write(dev, B43_PHY_BASE(0x5A), 0x0480);
-		b43_phy_write(dev, B43_PHY_BASE(0x59), 0xC810);
-		b43_phy_write(dev, B43_PHY_BASE(0x58), 0x000D);
+		b43_phy_write(dev, B43_PHY_CCK(0x5A), 0x0480);
+		b43_phy_write(dev, B43_PHY_CCK(0x59), 0xC810);
+		b43_phy_write(dev, B43_PHY_CCK(0x58), 0x000D);
 		if (phy->gmode || phy->rev >= 2) {
 			b43_phy_write(dev, B43_PHY_RFOVERVAL,
 				      radio2050_rfover_val(dev,
@@ -3912,7 +3692,7 @@ u16 b43_radio_init2050(struct b43_wldev *dev)
 		b43_phy_write(dev, B43_PHY_PGACTL, 0xFFF0);
 		udelay(20);
 		tmp1 += b43_phy_read(dev, B43_PHY_LO_LEAKAGE);
-		b43_phy_write(dev, B43_PHY_BASE(0x58), 0);
+		b43_phy_write(dev, B43_PHY_CCK(0x58), 0);
 		if (phy->gmode || phy->rev >= 2) {
 			b43_phy_write(dev, B43_PHY_RFOVERVAL,
 				      radio2050_rfover_val(dev,
@@ -3923,7 +3703,7 @@ u16 b43_radio_init2050(struct b43_wldev *dev)
 	}
 	udelay(10);
 
-	b43_phy_write(dev, B43_PHY_BASE(0x58), 0);
+	b43_phy_write(dev, B43_PHY_CCK(0x58), 0);
 	tmp1++;
 	tmp1 >>= 9;
 
@@ -3932,9 +3712,9 @@ u16 b43_radio_init2050(struct b43_wldev *dev)
 		b43_radio_write16(dev, 0x78, radio78);
 		udelay(10);
 		for (j = 0; j < 16; j++) {
-			b43_phy_write(dev, B43_PHY_BASE(0x5A), 0x0D80);
-			b43_phy_write(dev, B43_PHY_BASE(0x59), 0xC810);
-			b43_phy_write(dev, B43_PHY_BASE(0x58), 0x000D);
+			b43_phy_write(dev, B43_PHY_CCK(0x5A), 0x0D80);
+			b43_phy_write(dev, B43_PHY_CCK(0x59), 0xC810);
+			b43_phy_write(dev, B43_PHY_CCK(0x58), 0x000D);
 			if (phy->gmode || phy->rev >= 2) {
 				b43_phy_write(dev, B43_PHY_RFOVERVAL,
 					      radio2050_rfover_val(dev,
@@ -3963,7 +3743,7 @@ u16 b43_radio_init2050(struct b43_wldev *dev)
 			b43_phy_write(dev, B43_PHY_PGACTL, 0xFFF0);
 			udelay(10);
 			tmp2 += b43_phy_read(dev, B43_PHY_LO_LEAKAGE);
-			b43_phy_write(dev, B43_PHY_BASE(0x58), 0);
+			b43_phy_write(dev, B43_PHY_CCK(0x58), 0);
 			if (phy->gmode || phy->rev >= 2) {
 				b43_phy_write(dev, B43_PHY_RFOVERVAL,
 					      radio2050_rfover_val(dev,
@@ -3984,16 +3764,16 @@ u16 b43_radio_init2050(struct b43_wldev *dev)
 	b43_radio_write16(dev, 0x51, sav.radio_51);
 	b43_radio_write16(dev, 0x52, sav.radio_52);
 	b43_radio_write16(dev, 0x43, sav.radio_43);
-	b43_phy_write(dev, B43_PHY_BASE(0x5A), sav.phy_base_5A);
-	b43_phy_write(dev, B43_PHY_BASE(0x59), sav.phy_base_59);
-	b43_phy_write(dev, B43_PHY_BASE(0x58), sav.phy_base_58);
+	b43_phy_write(dev, B43_PHY_CCK(0x5A), sav.phy_cck_5A);
+	b43_phy_write(dev, B43_PHY_CCK(0x59), sav.phy_cck_59);
+	b43_phy_write(dev, B43_PHY_CCK(0x58), sav.phy_cck_58);
 	b43_write16(dev, 0x3E6, sav.reg_3E6);
 	if (phy->analog != 0)
 		b43_write16(dev, 0x3F4, sav.reg_3F4);
 	b43_phy_write(dev, B43_PHY_SYNCCTL, sav.phy_syncctl);
 	b43_synth_pu_workaround(dev, phy->channel);
 	if (phy->type == B43_PHYTYPE_B) {
-		b43_phy_write(dev, B43_PHY_BASE(0x30), sav.phy_base_30);
+		b43_phy_write(dev, B43_PHY_CCK(0x30), sav.phy_cck_30);
 		b43_write16(dev, 0x3EC, sav.reg_3EC);
 	} else if (phy->gmode) {
 		b43_write16(dev, B43_MMIO_PHY_RADIO,
@@ -4103,7 +3883,8 @@ int b43_radio_selectchannel(struct b43_wldev *dev,
 	struct b43_phy *phy = &dev->phy;
 	u16 r8, tmp;
 	u16 freq;
-	u16 channelcookie;
+	u16 channelcookie, savedcookie;
+	int err = 0;
 
 	if (channel == 0xFF) {
 		switch (phy->type) {
@@ -4114,6 +3895,10 @@ int b43_radio_selectchannel(struct b43_wldev *dev,
 		case B43_PHYTYPE_G:
 			channel = B43_DEFAULT_CHANNEL_BG;
 			break;
+		case B43_PHYTYPE_N:
+			//FIXME check if we are on 2.4GHz or 5GHz and set a default channel.
+			channel = 1;
+			break;
 		default:
 			B43_WARN_ON(1);
 		}
@@ -4123,13 +3908,18 @@ int b43_radio_selectchannel(struct b43_wldev *dev,
 	 * firmware from sending ghost packets.
 	 */
 	channelcookie = channel;
-	if (phy->type == B43_PHYTYPE_A)
+	if (0 /*FIXME on 5Ghz */)
 		channelcookie |= 0x100;
+	//FIXME set 40Mhz flag if required
+	savedcookie = b43_shm_read16(dev, B43_SHM_SHARED, B43_SHM_SH_CHAN);
 	b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_CHAN, channelcookie);
 
-	if (phy->type == B43_PHYTYPE_A) {
-		if (channel > 200)
-			return -EINVAL;
+	switch (phy->type) {
+	case B43_PHYTYPE_A:
+		if (channel > 200) {
+			err = -EINVAL;
+			goto out;
+		}
 		freq = channel2freq_a(channel);
 
 		r8 = b43_radio_read16(dev, 0x0008);
@@ -4176,9 +3966,12 @@ int b43_radio_selectchannel(struct b43_wldev *dev,
 		b43_radio_set_tx_iq(dev);
 		//TODO: TSSI2dbm workaround
 		b43_phy_xmitpower(dev);	//FIXME correct?
-	} else {
-		if ((channel < 1) || (channel > 14))
-			return -EINVAL;
+		break;
+	case B43_PHYTYPE_G:
+		if ((channel < 1) || (channel > 14)) {
+			err = -EINVAL;
+			goto out;
+		}
 
 		if (synthetic_pu_workaround)
 			b43_synth_pu_workaround(dev, channel);
@@ -4186,7 +3979,7 @@ int b43_radio_selectchannel(struct b43_wldev *dev,
 		b43_write16(dev, B43_MMIO_CHANNEL, channel2freq_bg(channel));
 
 		if (channel == 14) {
-			if (dev->dev->bus->sprom.r1.country_code ==
+			if (dev->dev->bus->sprom.country_code ==
 			    SSB_SPROM1CCODE_JAPAN)
 				b43_hf_write(dev,
 					     b43_hf_read(dev) & ~B43_HF_ACPR);
@@ -4201,110 +3994,25 @@ int b43_radio_selectchannel(struct b43_wldev *dev,
 				    b43_read16(dev, B43_MMIO_CHANNEL_EXT)
 				    & 0xF7BF);
 		}
+		break;
+	case B43_PHYTYPE_N:
+		err = b43_nphy_selectchannel(dev, channel);
+		if (err)
+			goto out;
+		break;
+	default:
+		B43_WARN_ON(1);
 	}
 
 	phy->channel = channel;
 	/* Wait for the radio to tune to the channel and stabilize. */
 	msleep(8);
-
-	return 0;
-}
-
-/* http://bcm-specs.sipsolutions.net/TX_Gain_Base_Band */
-static u16 b43_get_txgain_base_band(u16 txpower)
-{
-	u16 ret;
-
-	B43_WARN_ON(txpower > 63);
-
-	if (txpower >= 54)
-		ret = 2;
-	else if (txpower >= 49)
-		ret = 4;
-	else if (txpower >= 44)
-		ret = 5;
-	else
-		ret = 6;
-
-	return ret;
-}
-
-/* http://bcm-specs.sipsolutions.net/TX_Gain_Radio_Frequency_Power_Amplifier */
-static u16 b43_get_txgain_freq_power_amp(u16 txpower)
-{
-	u16 ret;
-
-	B43_WARN_ON(txpower > 63);
-
-	if (txpower >= 32)
-		ret = 0;
-	else if (txpower >= 25)
-		ret = 1;
-	else if (txpower >= 20)
-		ret = 2;
-	else if (txpower >= 12)
-		ret = 3;
-	else
-		ret = 4;
-
-	return ret;
-}
-
-/* http://bcm-specs.sipsolutions.net/TX_Gain_Digital_Analog_Converter */
-static u16 b43_get_txgain_dac(u16 txpower)
-{
-	u16 ret;
-
-	B43_WARN_ON(txpower > 63);
-
-	if (txpower >= 54)
-		ret = txpower - 53;
-	else if (txpower >= 49)
-		ret = txpower - 42;
-	else if (txpower >= 44)
-		ret = txpower - 37;
-	else if (txpower >= 32)
-		ret = txpower - 32;
-	else if (txpower >= 25)
-		ret = txpower - 20;
-	else if (txpower >= 20)
-		ret = txpower - 13;
-	else if (txpower >= 12)
-		ret = txpower - 8;
-	else
-		ret = txpower;
-
-	return ret;
-}
-
-static void b43_radio_set_txpower_a(struct b43_wldev *dev, u16 txpower)
-{
-	struct b43_phy *phy = &dev->phy;
-	u16 pamp, base, dac, t;
-
-	txpower = limit_value(txpower, 0, 63);
-
-	pamp = b43_get_txgain_freq_power_amp(txpower);
-	pamp <<= 5;
-	pamp &= 0x00E0;
-	b43_phy_write(dev, 0x0019, pamp);
-
-	base = b43_get_txgain_base_band(txpower);
-	base &= 0x000F;
-	b43_phy_write(dev, 0x0017, base | 0x0020);
-
-	t = b43_ofdmtab_read16(dev, 0x3000, 1);
-	t &= 0x0007;
-
-	dac = b43_get_txgain_dac(txpower);
-	dac <<= 3;
-	dac |= t;
-
-	b43_ofdmtab_write16(dev, 0x3000, 1, dac);
-
-	phy->txpwr_offset = txpower;
-
-	//TODO: FuncPlaceholder (Adjust BB loft cancel)
+out:
+	if (err) {
+		b43_shm_write16(dev, B43_SHM_SHARED,
+				B43_SHM_SH_CHAN, savedcookie);
+	}
+	return err;
 }
 
 void b43_radio_turn_on(struct b43_wldev *dev)
@@ -4344,6 +4052,9 @@ void b43_radio_turn_on(struct b43_wldev *dev)
 		err |= b43_radio_selectchannel(dev, channel, 0);
 		B43_WARN_ON(err);
 		break;
+	case B43_PHYTYPE_N:
+		b43_nphy_radio_turn_on(dev);
+		break;
 	default:
 		B43_WARN_ON(1);
 	}
@@ -4357,13 +4068,17 @@ void b43_radio_turn_off(struct b43_wldev *dev, bool force)
 	if (!phy->radio_on && !force)
 		return;
 
-	if (phy->type == B43_PHYTYPE_A) {
+	switch (phy->type) {
+	case B43_PHYTYPE_N:
+		b43_nphy_radio_turn_off(dev);
+		break;
+	case B43_PHYTYPE_A:
 		b43_radio_write16(dev, 0x0004, 0x00FF);
 		b43_radio_write16(dev, 0x0005, 0x00FB);
 		b43_phy_write(dev, 0x0010, b43_phy_read(dev, 0x0010) | 0x0008);
 		b43_phy_write(dev, 0x0011, b43_phy_read(dev, 0x0011) | 0x0008);
-	}
-	if (phy->type == B43_PHYTYPE_G && dev->dev->id.revision >= 5) {
+		break;
+	case B43_PHYTYPE_G: {
 		u16 rfover, rfoverval;
 
 		rfover = b43_phy_read(dev, B43_PHY_RFOVER);
@@ -4375,7 +4090,10 @@ void b43_radio_turn_off(struct b43_wldev *dev, bool force)
 		}
 		b43_phy_write(dev, B43_PHY_RFOVER, rfover | 0x008C);
 		b43_phy_write(dev, B43_PHY_RFOVERVAL, rfoverval & 0xFF73);
-	} else
-		b43_phy_write(dev, 0x0015, 0xAA00);
+		break;
+	}
+	default:
+		B43_WARN_ON(1);
+	}
 	phy->radio_on = 0;
 }
diff --git a/package/b43/src/phy.h b/package/b43/src/phy.h
index c64d74504f..6d165d8221 100644
--- a/package/b43/src/phy.h
+++ b/package/b43/src/phy.h
@@ -9,14 +9,21 @@ struct b43_phy;
 /*** PHY Registers ***/
 
 /* Routing */
-#define B43_PHYROUTE_OFDM_GPHY		0x400
-#define B43_PHYROUTE_EXT_GPHY		0x800
-
-/* Base registers. */
-#define B43_PHY_BASE(reg)		(reg)
-/* OFDM (A) registers of a G-PHY */
+#define B43_PHYROUTE			0x0C00 /* PHY register routing bits mask */
+#define  B43_PHYROUTE_BASE		0x0000 /* Base registers */
+#define  B43_PHYROUTE_OFDM_GPHY		0x0400 /* OFDM register routing for G-PHYs */
+#define  B43_PHYROUTE_EXT_GPHY		0x0800 /* Extended G-PHY registers */
+#define  B43_PHYROUTE_N_BMODE		0x0C00 /* N-PHY BMODE registers */
+
+/* CCK (B-PHY) registers. */
+#define B43_PHY_CCK(reg)		((reg) | B43_PHYROUTE_BASE)
+/* N-PHY registers. */
+#define B43_PHY_N(reg)			((reg) | B43_PHYROUTE_BASE)
+/* N-PHY BMODE registers. */
+#define B43_PHY_N_BMODE(reg)		((reg) | B43_PHYROUTE_N_BMODE)
+/* OFDM (A-PHY) registers. */
 #define B43_PHY_OFDM(reg)		((reg) | B43_PHYROUTE_OFDM_GPHY)
-/* Extended G-PHY registers */
+/* Extended G-PHY registers. */
 #define B43_PHY_EXTG(reg)		((reg) | B43_PHYROUTE_EXT_GPHY)
 
 /* OFDM (A) PHY Registers */
@@ -25,10 +32,13 @@ struct b43_phy;
 #define  B43_PHY_BBANDCFG_RXANT		0x180	/* RX Antenna selection */
 #define  B43_PHY_BBANDCFG_RXANT_SHIFT	7
 #define B43_PHY_PWRDOWN			B43_PHY_OFDM(0x03)	/* Powerdown */
-#define B43_PHY_CRSTHRES1		B43_PHY_OFDM(0x06)	/* CRS Threshold 1 */
+#define B43_PHY_CRSTHRES1_R1		B43_PHY_OFDM(0x06)	/* CRS Threshold 1 (phy.rev 1 only) */
 #define B43_PHY_LNAHPFCTL		B43_PHY_OFDM(0x1C)	/* LNA/HPF control */
+#define B43_PHY_LPFGAINCTL		B43_PHY_OFDM(0x20)	/* LPF Gain control */
 #define B43_PHY_ADIVRELATED		B43_PHY_OFDM(0x27)	/* FIXME rename */
 #define B43_PHY_CRS0			B43_PHY_OFDM(0x29)
+#define  B43_PHY_CRS0_EN		0x4000
+#define B43_PHY_PEAK_COUNT		B43_PHY_OFDM(0x30)
 #define B43_PHY_ANTDWELL		B43_PHY_OFDM(0x2B)	/* Antenna dwell */
 #define  B43_PHY_ANTDWELL_AUTODIV1	0x0100	/* Automatic RX diversity start antenna */
 #define B43_PHY_ENCORE			B43_PHY_OFDM(0x49)	/* "Encore" (RangeMax / BroadRange) */
@@ -37,6 +47,7 @@ struct b43_phy;
 #define B43_PHY_OFDM61			B43_PHY_OFDM(0x61)	/* FIXME rename */
 #define  B43_PHY_OFDM61_10		0x0010	/* FIXME rename */
 #define B43_PHY_IQBAL			B43_PHY_OFDM(0x69)	/* I/Q balance */
+#define B43_PHY_BBTXDC_BIAS		B43_PHY_OFDM(0x6B)	/* Baseband TX DC bias */
 #define B43_PHY_OTABLECTL		B43_PHY_OFDM(0x72)	/* OFDM table control (see below) */
 #define  B43_PHY_OTABLEOFF		0x03FF	/* OFDM table offset (see below) */
 #define  B43_PHY_OTABLENR		0xFC00	/* OFDM table number (see below) */
@@ -44,6 +55,9 @@ struct b43_phy;
 #define B43_PHY_OTABLEI			B43_PHY_OFDM(0x73)	/* OFDM table data I */
 #define B43_PHY_OTABLEQ			B43_PHY_OFDM(0x74)	/* OFDM table data Q */
 #define B43_PHY_HPWR_TSSICTL		B43_PHY_OFDM(0x78)	/* Hardware power TSSI control */
+#define B43_PHY_ADCCTL			B43_PHY_OFDM(0x7A)	/* ADC control */
+#define B43_PHY_IDLE_TSSI		B43_PHY_OFDM(0x7B)
+#define B43_PHY_A_TEMP_SENSE		B43_PHY_OFDM(0x7C)	/* A PHY temperature sense */
 #define B43_PHY_NRSSITHRES		B43_PHY_OFDM(0x8A)	/* NRSSI threshold */
 #define B43_PHY_ANTWRSETT		B43_PHY_OFDM(0x8C)	/* Antenna WR settle */
 #define  B43_PHY_ANTWRSETT_ARXDIV	0x2000	/* Automatic RX diversity enabled */
@@ -54,33 +68,35 @@ struct b43_phy;
 #define B43_PHY_N1N2GAIN		B43_PHY_OFDM(0xA2)
 #define B43_PHY_CLIPTHRES		B43_PHY_OFDM(0xA3)
 #define B43_PHY_CLIPN1P2THRES		B43_PHY_OFDM(0xA4)
+#define B43_PHY_CCKSHIFTBITS_WA		B43_PHY_OFDM(0xA5)	/* CCK shiftbits workaround, FIXME rename */
+#define B43_PHY_CCKSHIFTBITS		B43_PHY_OFDM(0xA7)	/* FIXME rename */
 #define B43_PHY_DIVSRCHIDX		B43_PHY_OFDM(0xA8)	/* Divider search gain/index */
 #define B43_PHY_CLIPP2THRES		B43_PHY_OFDM(0xA9)
 #define B43_PHY_CLIPP3THRES		B43_PHY_OFDM(0xAA)
 #define B43_PHY_DIVP1P2GAIN		B43_PHY_OFDM(0xAB)
 #define B43_PHY_DIVSRCHGAINBACK		B43_PHY_OFDM(0xAD)	/* Divider search gain back */
 #define B43_PHY_DIVSRCHGAINCHNG		B43_PHY_OFDM(0xAE)	/* Divider search gain change */
-#define B43_PHY_CRSTHRES1_R1		B43_PHY_OFDM(0xC0)	/* CRS Threshold 1 (rev 1 only) */
-#define B43_PHY_CRSTHRES2_R1		B43_PHY_OFDM(0xC1)	/* CRS Threshold 2 (rev 1 only) */
+#define B43_PHY_CRSTHRES1		B43_PHY_OFDM(0xC0)	/* CRS Threshold 1 (phy.rev >= 2 only) */
+#define B43_PHY_CRSTHRES2		B43_PHY_OFDM(0xC1)	/* CRS Threshold 2 (phy.rev >= 2 only) */
 #define B43_PHY_TSSIP_LTBASE		B43_PHY_OFDM(0x380)	/* TSSI power lookup table base */
 #define B43_PHY_DC_LTBASE		B43_PHY_OFDM(0x3A0)	/* DC lookup table base */
 #define B43_PHY_GAIN_LTBASE		B43_PHY_OFDM(0x3C0)	/* Gain lookup table base */
 
 /* CCK (B) PHY Registers */
-#define B43_PHY_VERSION_CCK		B43_PHY_BASE(0x00)	/* Versioning register for B-PHY */
-#define B43_PHY_CCKBBANDCFG		B43_PHY_BASE(0x01)	/* Contains antenna 0/1 control bit */
-#define B43_PHY_PGACTL			B43_PHY_BASE(0x15)	/* PGA control */
+#define B43_PHY_VERSION_CCK		B43_PHY_CCK(0x00)	/* Versioning register for B-PHY */
+#define B43_PHY_CCKBBANDCFG		B43_PHY_CCK(0x01)	/* Contains antenna 0/1 control bit */
+#define B43_PHY_PGACTL			B43_PHY_CCK(0x15)	/* PGA control */
 #define  B43_PHY_PGACTL_LPF		0x1000	/* Low pass filter (?) */
 #define  B43_PHY_PGACTL_LOWBANDW	0x0040	/* Low bandwidth flag */
 #define  B43_PHY_PGACTL_UNKNOWN		0xEFA0
-#define B43_PHY_FBCTL1			B43_PHY_BASE(0x18)	/* Frequency bandwidth control 1 */
-#define B43_PHY_ITSSI			B43_PHY_BASE(0x29)	/* Idle TSSI */
-#define B43_PHY_LO_LEAKAGE		B43_PHY_BASE(0x2D)	/* Measured LO leakage */
-#define B43_PHY_ENERGY			B43_PHY_BASE(0x33)	/* Energy */
-#define B43_PHY_SYNCCTL			B43_PHY_BASE(0x35)
-#define B43_PHY_FBCTL2			B43_PHY_BASE(0x38)	/* Frequency bandwidth control 2 */
-#define B43_PHY_DACCTL			B43_PHY_BASE(0x60)	/* DAC control */
-#define B43_PHY_RCCALOVER		B43_PHY_BASE(0x78)	/* RC calibration override */
+#define B43_PHY_FBCTL1			B43_PHY_CCK(0x18)	/* Frequency bandwidth control 1 */
+#define B43_PHY_ITSSI			B43_PHY_CCK(0x29)	/* Idle TSSI */
+#define B43_PHY_LO_LEAKAGE		B43_PHY_CCK(0x2D)	/* Measured LO leakage */
+#define B43_PHY_ENERGY			B43_PHY_CCK(0x33)	/* Energy */
+#define B43_PHY_SYNCCTL			B43_PHY_CCK(0x35)
+#define B43_PHY_FBCTL2			B43_PHY_CCK(0x38)	/* Frequency bandwidth control 2 */
+#define B43_PHY_DACCTL			B43_PHY_CCK(0x60)	/* DAC control */
+#define B43_PHY_RCCALOVER		B43_PHY_CCK(0x78)	/* RC calibration override */
 
 /* Extended G-PHY Registers */
 #define B43_PHY_CLASSCTL		B43_PHY_EXTG(0x02)	/* Classify control */
@@ -125,13 +141,14 @@ struct b43_phy;
 #define B43_OFDMTAB_DC			B43_OFDMTAB(0x0E, 7)
 #define B43_OFDMTAB_PWRDYN2		B43_OFDMTAB(0x0E, 12)
 #define B43_OFDMTAB_LNAGAIN		B43_OFDMTAB(0x0E, 13)
-//TODO
+#define B43_OFDMTAB_UNKNOWN_0F		B43_OFDMTAB(0x0F, 0)	//TODO rename
+#define B43_OFDMTAB_UNKNOWN_APHY	B43_OFDMTAB(0x0F, 7)	//TODO rename
 #define B43_OFDMTAB_LPFGAIN		B43_OFDMTAB(0x0F, 12)
 #define B43_OFDMTAB_RSSI		B43_OFDMTAB(0x10, 0)
-//TODO
+#define B43_OFDMTAB_UNKNOWN_11		B43_OFDMTAB(0x11, 4)	//TODO rename
 #define B43_OFDMTAB_AGC1_R1		B43_OFDMTAB(0x13, 0)
-#define B43_OFDMTAB_GAINX_R1		B43_OFDMTAB(0x14, 0)	//TODO rename
-#define B43_OFDMTAB_MINSIGSQ		B43_OFDMTAB(0x14, 1)
+#define B43_OFDMTAB_GAINX_R1		B43_OFDMTAB(0x14, 0)	//TODO remove!
+#define B43_OFDMTAB_MINSIGSQ		B43_OFDMTAB(0x14, 0)
 #define B43_OFDMTAB_AGC3_R1		B43_OFDMTAB(0x15, 0)
 #define B43_OFDMTAB_WRSSI_R1		B43_OFDMTAB(0x15, 4)
 #define B43_OFDMTAB_TSSI		B43_OFDMTAB(0x15, 0)
@@ -163,6 +180,8 @@ enum {
 	B43_ANTENNA1,		/* Antenna 0 */
 	B43_ANTENNA_AUTO1,	/* Automatic, starting with antenna 1 */
 	B43_ANTENNA_AUTO0,	/* Automatic, starting with antenna 0 */
+	B43_ANTENNA2,
+	B43_ANTENNA3 = 8,
 
 	B43_ANTENNA_AUTO = B43_ANTENNA_AUTO0,
 	B43_ANTENNA_DEFAULT = B43_ANTENNA_AUTO,
@@ -182,21 +201,21 @@ enum {
 #define B43_PHYVER_TYPE_SHIFT		8
 #define B43_PHYVER_VERSION		0x00FF
 
-void b43_raw_phy_lock(struct b43_wldev *dev);
-#define b43_phy_lock(dev, flags) \
-	do {					\
-		local_irq_save(flags);		\
-		b43_raw_phy_lock(dev);	\
-	} while (0)
-void b43_raw_phy_unlock(struct b43_wldev *dev);
-#define b43_phy_unlock(dev, flags) \
-	do {					\
-		b43_raw_phy_unlock(dev);	\
-		local_irq_restore(flags);	\
-	} while (0)
+void b43_phy_lock(struct b43_wldev *dev);
+void b43_phy_unlock(struct b43_wldev *dev);
+
 
+/* Read a value from a PHY register */
 u16 b43_phy_read(struct b43_wldev *dev, u16 offset);
+/* Write a value to a PHY register */
 void b43_phy_write(struct b43_wldev *dev, u16 offset, u16 val);
+/* Mask a PHY register with a mask */
+void b43_phy_mask(struct b43_wldev *dev, u16 offset, u16 mask);
+/* OR a PHY register with a bitmap */
+void b43_phy_set(struct b43_wldev *dev, u16 offset, u16 set);
+/* Mask and OR a PHY register with a mask and bitmap */
+void b43_phy_maskset(struct b43_wldev *dev, u16 offset, u16 mask, u16 set);
+
 
 int b43_phy_init_tssi2dbm_table(struct b43_wldev *dev);
 
@@ -260,8 +279,18 @@ extern const u8 b43_radio_channel_codes_bg[];
 void b43_radio_lock(struct b43_wldev *dev);
 void b43_radio_unlock(struct b43_wldev *dev);
 
+
+/* Read a value from a 16bit radio register */
 u16 b43_radio_read16(struct b43_wldev *dev, u16 offset);
+/* Write a value to a 16bit radio register */
 void b43_radio_write16(struct b43_wldev *dev, u16 offset, u16 val);
+/* Mask a 16bit radio register with a mask */
+void b43_radio_mask(struct b43_wldev *dev, u16 offset, u16 mask);
+/* OR a 16bit radio register with a bitmap */
+void b43_radio_set(struct b43_wldev *dev, u16 offset, u16 set);
+/* Mask and OR a PHY register with a mask and bitmap */
+void b43_radio_maskset(struct b43_wldev *dev, u16 offset, u16 mask, u16 set);
+
 
 u16 b43_radio_init2050(struct b43_wldev *dev);
 void b43_radio_init2060(struct b43_wldev *dev);
diff --git a/package/b43/src/pio.c b/package/b43/src/pio.c
deleted file mode 100644
index 67752a28eb..0000000000
--- a/package/b43/src/pio.c
+++ /dev/null
@@ -1,652 +0,0 @@
-/*
-
-  Broadcom B43 wireless driver
-
-  PIO Transmission
-
-  Copyright (c) 2005 Michael Buesch <mb@bu3sch.de>
-
-  This program is free software; you can redistribute it and/or modify
-  it under the terms of the GNU General Public License as published by
-  the Free Software Foundation; either version 2 of the License, or
-  (at your option) any later version.
-
-  This program is distributed in the hope that it will be useful,
-  but WITHOUT ANY WARRANTY; without even the implied warranty of
-  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-  GNU General Public License for more details.
-
-  You should have received a copy of the GNU General Public License
-  along with this program; see the file COPYING.  If not, write to
-  the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
-  Boston, MA 02110-1301, USA.
-
-*/
-
-#include "b43.h"
-#include "pio.h"
-#include "main.h"
-#include "xmit.h"
-
-#include <linux/delay.h>
-
-static void tx_start(struct b43_pioqueue *queue)
-{
-	b43_pio_write(queue, B43_PIO_TXCTL, B43_PIO_TXCTL_INIT);
-}
-
-static void tx_octet(struct b43_pioqueue *queue, u8 octet)
-{
-	if (queue->need_workarounds) {
-		b43_pio_write(queue, B43_PIO_TXDATA, octet);
-		b43_pio_write(queue, B43_PIO_TXCTL, B43_PIO_TXCTL_WRITELO);
-	} else {
-		b43_pio_write(queue, B43_PIO_TXCTL, B43_PIO_TXCTL_WRITELO);
-		b43_pio_write(queue, B43_PIO_TXDATA, octet);
-	}
-}
-
-static u16 tx_get_next_word(const u8 * txhdr,
-			    const u8 * packet,
-			    size_t txhdr_size, unsigned int *pos)
-{
-	const u8 *source;
-	unsigned int i = *pos;
-	u16 ret;
-
-	if (i < txhdr_size) {
-		source = txhdr;
-	} else {
-		source = packet;
-		i -= txhdr_size;
-	}
-	ret = le16_to_cpu(*((__le16 *)(source + i)));
-	*pos += 2;
-
-	return ret;
-}
-
-static void tx_data(struct b43_pioqueue *queue,
-		    u8 * txhdr, const u8 * packet, unsigned int octets)
-{
-	u16 data;
-	unsigned int i = 0;
-
-	if (queue->need_workarounds) {
-		data = tx_get_next_word(txhdr, packet,
-					sizeof(struct b43_txhdr_fw4), &i);
-		b43_pio_write(queue, B43_PIO_TXDATA, data);
-	}
-	b43_pio_write(queue, B43_PIO_TXCTL,
-		      B43_PIO_TXCTL_WRITELO | B43_PIO_TXCTL_WRITEHI);
-	while (i < octets - 1) {
-		data = tx_get_next_word(txhdr, packet,
-					sizeof(struct b43_txhdr_fw4), &i);
-		b43_pio_write(queue, B43_PIO_TXDATA, data);
-	}
-	if (octets % 2)
-		tx_octet(queue,
-			 packet[octets - sizeof(struct b43_txhdr_fw4) - 1]);
-}
-
-static void tx_complete(struct b43_pioqueue *queue, struct sk_buff *skb)
-{
-	if (queue->need_workarounds) {
-		b43_pio_write(queue, B43_PIO_TXDATA, skb->data[skb->len - 1]);
-		b43_pio_write(queue, B43_PIO_TXCTL,
-			      B43_PIO_TXCTL_WRITELO | B43_PIO_TXCTL_COMPLETE);
-	} else {
-		b43_pio_write(queue, B43_PIO_TXCTL, B43_PIO_TXCTL_COMPLETE);
-	}
-}
-
-static u16 generate_cookie(struct b43_pioqueue *queue,
-			   struct b43_pio_txpacket *packet)
-{
-	u16 cookie = 0x0000;
-	u16 packetindex;
-
-	/* We use the upper 4 bits for the PIO
-	 * controller ID and the lower 12 bits
-	 * for the packet index (in the cache).
-	 */
-	switch (queue->mmio_base) {
-	case B43_MMIO_PIO1_BASE:
-		break;
-	case B43_MMIO_PIO2_BASE:
-		cookie = 0x1000;
-		break;
-	case B43_MMIO_PIO3_BASE:
-		cookie = 0x2000;
-		break;
-	case B43_MMIO_PIO4_BASE:
-		cookie = 0x3000;
-		break;
-	default:
-		B43_WARN_ON(1);
-	}
-	packetindex = packet->index;
-	B43_WARN_ON(packetindex & ~0x0FFF);
-	cookie |= (u16) packetindex;
-
-	return cookie;
-}
-
-static
-struct b43_pioqueue *parse_cookie(struct b43_wldev *dev,
-				  u16 cookie, struct b43_pio_txpacket **packet)
-{
-	struct b43_pio *pio = &dev->pio;
-	struct b43_pioqueue *queue = NULL;
-	int packetindex;
-
-	switch (cookie & 0xF000) {
-	case 0x0000:
-		queue = pio->queue0;
-		break;
-	case 0x1000:
-		queue = pio->queue1;
-		break;
-	case 0x2000:
-		queue = pio->queue2;
-		break;
-	case 0x3000:
-		queue = pio->queue3;
-		break;
-	default:
-		B43_WARN_ON(1);
-	}
-	packetindex = (cookie & 0x0FFF);
-	B43_WARN_ON(!(packetindex >= 0 && packetindex < B43_PIO_MAXTXPACKETS));
-	*packet = &(queue->tx_packets_cache[packetindex]);
-
-	return queue;
-}
-
-union txhdr_union {
-	struct b43_txhdr_fw4 txhdr_fw4;
-};
-
-static void pio_tx_write_fragment(struct b43_pioqueue *queue,
-				  struct sk_buff *skb,
-				  struct b43_pio_txpacket *packet,
-				  size_t txhdr_size)
-{
-	union txhdr_union txhdr_data;
-	u8 *txhdr = NULL;
-	unsigned int octets;
-
-	txhdr = (u8 *) (&txhdr_data.txhdr_fw4);
-
-	B43_WARN_ON(skb_shinfo(skb)->nr_frags);
-	b43_generate_txhdr(queue->dev,
-			   txhdr, skb->data, skb->len,
-			   &packet->txstat.control,
-			   generate_cookie(queue, packet));
-
-	tx_start(queue);
-	octets = skb->len + txhdr_size;
-	if (queue->need_workarounds)
-		octets--;
-	tx_data(queue, txhdr, (u8 *) skb->data, octets);
-	tx_complete(queue, skb);
-}
-
-static void free_txpacket(struct b43_pio_txpacket *packet)
-{
-	struct b43_pioqueue *queue = packet->queue;
-
-	if (packet->skb)
-		dev_kfree_skb_any(packet->skb);
-	list_move(&packet->list, &queue->txfree);
-	queue->nr_txfree++;
-}
-
-static int pio_tx_packet(struct b43_pio_txpacket *packet)
-{
-	struct b43_pioqueue *queue = packet->queue;
-	struct sk_buff *skb = packet->skb;
-	u16 octets;
-
-	octets = (u16) skb->len + sizeof(struct b43_txhdr_fw4);
-	if (queue->tx_devq_size < octets) {
-		b43warn(queue->dev->wl, "PIO queue too small. "
-			"Dropping packet.\n");
-		/* Drop it silently (return success) */
-		free_txpacket(packet);
-		return 0;
-	}
-	B43_WARN_ON(queue->tx_devq_packets > B43_PIO_MAXTXDEVQPACKETS);
-	B43_WARN_ON(queue->tx_devq_used > queue->tx_devq_size);
-	/* Check if there is sufficient free space on the device
-	 * TX queue. If not, return and let the TX tasklet
-	 * retry later.
-	 */
-	if (queue->tx_devq_packets == B43_PIO_MAXTXDEVQPACKETS)
-		return -EBUSY;
-	if (queue->tx_devq_used + octets > queue->tx_devq_size)
-		return -EBUSY;
-	/* Now poke the device. */
-	pio_tx_write_fragment(queue, skb, packet, sizeof(struct b43_txhdr_fw4));
-
-	/* Account for the packet size.
-	 * (We must not overflow the device TX queue)
-	 */
-	queue->tx_devq_packets++;
-	queue->tx_devq_used += octets;
-
-	/* Transmission started, everything ok, move the
-	 * packet to the txrunning list.
-	 */
-	list_move_tail(&packet->list, &queue->txrunning);
-
-	return 0;
-}
-
-static void tx_tasklet(unsigned long d)
-{
-	struct b43_pioqueue *queue = (struct b43_pioqueue *)d;
-	struct b43_wldev *dev = queue->dev;
-	unsigned long flags;
-	struct b43_pio_txpacket *packet, *tmp_packet;
-	int err;
-	u16 txctl;
-
-	spin_lock_irqsave(&dev->wl->irq_lock, flags);
-	if (queue->tx_frozen)
-		goto out_unlock;
-	txctl = b43_pio_read(queue, B43_PIO_TXCTL);
-	if (txctl & B43_PIO_TXCTL_SUSPEND)
-		goto out_unlock;
-
-	list_for_each_entry_safe(packet, tmp_packet, &queue->txqueue, list) {
-		/* Try to transmit the packet. This can fail, if
-		 * the device queue is full. In case of failure, the
-		 * packet is left in the txqueue.
-		 * If transmission succeed, the packet is moved to txrunning.
-		 * If it is impossible to transmit the packet, it
-		 * is dropped.
-		 */
-		err = pio_tx_packet(packet);
-		if (err)
-			break;
-	}
-      out_unlock:
-	spin_unlock_irqrestore(&dev->wl->irq_lock, flags);
-}
-
-static void setup_txqueues(struct b43_pioqueue *queue)
-{
-	struct b43_pio_txpacket *packet;
-	int i;
-
-	queue->nr_txfree = B43_PIO_MAXTXPACKETS;
-	for (i = 0; i < B43_PIO_MAXTXPACKETS; i++) {
-		packet = &(queue->tx_packets_cache[i]);
-
-		packet->queue = queue;
-		INIT_LIST_HEAD(&packet->list);
-		packet->index = i;
-
-		list_add(&packet->list, &queue->txfree);
-	}
-}
-
-static
-struct b43_pioqueue *b43_setup_pioqueue(struct b43_wldev *dev,
-					u16 pio_mmio_base)
-{
-	struct b43_pioqueue *queue;
-	u16 qsize;
-
-	queue = kzalloc(sizeof(*queue), GFP_KERNEL);
-	if (!queue)
-		goto out;
-
-	queue->dev = dev;
-	queue->mmio_base = pio_mmio_base;
-	queue->need_workarounds = (dev->dev->id.revision < 3);
-
-	INIT_LIST_HEAD(&queue->txfree);
-	INIT_LIST_HEAD(&queue->txqueue);
-	INIT_LIST_HEAD(&queue->txrunning);
-	tasklet_init(&queue->txtask, tx_tasklet, (unsigned long)queue);
-
-	b43_write32(dev, B43_MMIO_MACCTL, b43_read32(dev, B43_MMIO_MACCTL)
-		    & ~B43_MACCTL_BE);
-
-	qsize = b43_read16(dev, queue->mmio_base + B43_PIO_TXQBUFSIZE);
-	if (qsize == 0) {
-		b43err(dev->wl, "This card does not support PIO "
-		       "operation mode. Please use DMA mode "
-		       "(module parameter pio=0).\n");
-		goto err_freequeue;
-	}
-	if (qsize <= B43_PIO_TXQADJUST) {
-		b43err(dev->wl, "PIO tx device-queue too small (%u)\n", qsize);
-		goto err_freequeue;
-	}
-	qsize -= B43_PIO_TXQADJUST;
-	queue->tx_devq_size = qsize;
-
-	setup_txqueues(queue);
-
-      out:
-	return queue;
-
-      err_freequeue:
-	kfree(queue);
-	queue = NULL;
-	goto out;
-}
-
-static void cancel_transfers(struct b43_pioqueue *queue)
-{
-	struct b43_pio_txpacket *packet, *tmp_packet;
-
-	tasklet_disable(&queue->txtask);
-
-	list_for_each_entry_safe(packet, tmp_packet, &queue->txrunning, list)
-	    free_txpacket(packet);
-	list_for_each_entry_safe(packet, tmp_packet, &queue->txqueue, list)
-	    free_txpacket(packet);
-}
-
-static void b43_destroy_pioqueue(struct b43_pioqueue *queue)
-{
-	if (!queue)
-		return;
-
-	cancel_transfers(queue);
-	kfree(queue);
-}
-
-void b43_pio_free(struct b43_wldev *dev)
-{
-	struct b43_pio *pio;
-
-	if (!b43_using_pio(dev))
-		return;
-	pio = &dev->pio;
-
-	b43_destroy_pioqueue(pio->queue3);
-	pio->queue3 = NULL;
-	b43_destroy_pioqueue(pio->queue2);
-	pio->queue2 = NULL;
-	b43_destroy_pioqueue(pio->queue1);
-	pio->queue1 = NULL;
-	b43_destroy_pioqueue(pio->queue0);
-	pio->queue0 = NULL;
-}
-
-int b43_pio_init(struct b43_wldev *dev)
-{
-	struct b43_pio *pio = &dev->pio;
-	struct b43_pioqueue *queue;
-	int err = -ENOMEM;
-
-	queue = b43_setup_pioqueue(dev, B43_MMIO_PIO1_BASE);
-	if (!queue)
-		goto out;
-	pio->queue0 = queue;
-
-	queue = b43_setup_pioqueue(dev, B43_MMIO_PIO2_BASE);
-	if (!queue)
-		goto err_destroy0;
-	pio->queue1 = queue;
-
-	queue = b43_setup_pioqueue(dev, B43_MMIO_PIO3_BASE);
-	if (!queue)
-		goto err_destroy1;
-	pio->queue2 = queue;
-
-	queue = b43_setup_pioqueue(dev, B43_MMIO_PIO4_BASE);
-	if (!queue)
-		goto err_destroy2;
-	pio->queue3 = queue;
-
-	if (dev->dev->id.revision < 3)
-		dev->irq_savedstate |= B43_IRQ_PIO_WORKAROUND;
-
-	b43dbg(dev->wl, "PIO initialized\n");
-	err = 0;
-      out:
-	return err;
-
-      err_destroy2:
-	b43_destroy_pioqueue(pio->queue2);
-	pio->queue2 = NULL;
-      err_destroy1:
-	b43_destroy_pioqueue(pio->queue1);
-	pio->queue1 = NULL;
-      err_destroy0:
-	b43_destroy_pioqueue(pio->queue0);
-	pio->queue0 = NULL;
-	goto out;
-}
-
-int b43_pio_tx(struct b43_wldev *dev,
-	       struct sk_buff *skb, struct ieee80211_tx_control *ctl)
-{
-	struct b43_pioqueue *queue = dev->pio.queue1;
-	struct b43_pio_txpacket *packet;
-
-	B43_WARN_ON(queue->tx_suspended);
-	B43_WARN_ON(list_empty(&queue->txfree));
-
-	packet = list_entry(queue->txfree.next, struct b43_pio_txpacket, list);
-	packet->skb = skb;
-
-	memset(&packet->txstat, 0, sizeof(packet->txstat));
-	memcpy(&packet->txstat.control, ctl, sizeof(*ctl));
-
-	list_move_tail(&packet->list, &queue->txqueue);
-	queue->nr_txfree--;
-	queue->nr_tx_packets++;
-	B43_WARN_ON(queue->nr_txfree >= B43_PIO_MAXTXPACKETS);
-
-	tasklet_schedule(&queue->txtask);
-
-	return 0;
-}
-
-void b43_pio_handle_txstatus(struct b43_wldev *dev,
-			     const struct b43_txstatus *status)
-{
-	struct b43_pioqueue *queue;
-	struct b43_pio_txpacket *packet;
-
-	queue = parse_cookie(dev, status->cookie, &packet);
-	if (B43_WARN_ON(!queue))
-		return;
-
-	queue->tx_devq_packets--;
-	queue->tx_devq_used -=
-	    (packet->skb->len + sizeof(struct b43_txhdr_fw4));
-
-	if (status->acked) {
-		packet->txstat.flags |= IEEE80211_TX_STATUS_ACK;
-	} else {
-		if (!(packet->txstat.control.flags & IEEE80211_TXCTL_NO_ACK))
-			packet->txstat.excessive_retries = 1;
-	}
-	if (status->frame_count == 0) {
-		/* The frame was not transmitted at all. */
-		packet->txstat.retry_count = 0;
-	} else
-		packet->txstat.retry_count = status->frame_count - 1;
-	ieee80211_tx_status_irqsafe(dev->wl->hw, packet->skb,
-				    &(packet->txstat));
-	packet->skb = NULL;
-
-	free_txpacket(packet);
-	/* If there are packets on the txqueue, poke the tasklet
-	 * to transmit them.
-	 */
-	if (!list_empty(&queue->txqueue))
-		tasklet_schedule(&queue->txtask);
-}
-
-void b43_pio_get_tx_stats(struct b43_wldev *dev,
-			  struct ieee80211_tx_queue_stats *stats)
-{
-	struct b43_pio *pio = &dev->pio;
-	struct b43_pioqueue *queue;
-	struct ieee80211_tx_queue_stats_data *data;
-
-	queue = pio->queue1;
-	data = &(stats->data[0]);
-	data->len = B43_PIO_MAXTXPACKETS - queue->nr_txfree;
-	data->limit = B43_PIO_MAXTXPACKETS;
-	data->count = queue->nr_tx_packets;
-}
-
-static void pio_rx_error(struct b43_pioqueue *queue,
-			 int clear_buffers, const char *error)
-{
-	int i;
-
-	b43err(queue->dev->wl, "PIO RX error: %s\n", error);
-	b43_pio_write(queue, B43_PIO_RXCTL, B43_PIO_RXCTL_READY);
-	if (clear_buffers) {
-		B43_WARN_ON(queue->mmio_base != B43_MMIO_PIO1_BASE);
-		for (i = 0; i < 15; i++) {
-			/* Dummy read. */
-			b43_pio_read(queue, B43_PIO_RXDATA);
-		}
-	}
-}
-
-void b43_pio_rx(struct b43_pioqueue *queue)
-{
-	__le16 preamble[21] = { 0 };
-	struct b43_rxhdr_fw4 *rxhdr;
-	u16 tmp, len;
-	u32 macstat;
-	int i, preamble_readwords;
-	struct sk_buff *skb;
-
-	tmp = b43_pio_read(queue, B43_PIO_RXCTL);
-	if (!(tmp & B43_PIO_RXCTL_DATAAVAILABLE))
-		return;
-	b43_pio_write(queue, B43_PIO_RXCTL, B43_PIO_RXCTL_DATAAVAILABLE);
-
-	for (i = 0; i < 10; i++) {
-		tmp = b43_pio_read(queue, B43_PIO_RXCTL);
-		if (tmp & B43_PIO_RXCTL_READY)
-			goto data_ready;
-		udelay(10);
-	}
-	b43dbg(queue->dev->wl, "PIO RX timed out\n");
-	return;
-data_ready:
-
-	len = b43_pio_read(queue, B43_PIO_RXDATA);
-	if (unlikely(len > 0x700)) {
-		pio_rx_error(queue, 0, "len > 0x700");
-		return;
-	}
-	if (unlikely(len == 0 && queue->mmio_base != B43_MMIO_PIO4_BASE)) {
-		pio_rx_error(queue, 0, "len == 0");
-		return;
-	}
-	preamble[0] = cpu_to_le16(len);
-	if (queue->mmio_base == B43_MMIO_PIO4_BASE)
-		preamble_readwords = 14 / sizeof(u16);
-	else
-		preamble_readwords = 18 / sizeof(u16);
-	for (i = 0; i < preamble_readwords; i++) {
-		tmp = b43_pio_read(queue, B43_PIO_RXDATA);
-		preamble[i + 1] = cpu_to_le16(tmp);
-	}
-	rxhdr = (struct b43_rxhdr_fw4 *)preamble;
-	macstat = le32_to_cpu(rxhdr->mac_status);
-	if (macstat & B43_RX_MAC_FCSERR) {
-		pio_rx_error(queue,
-			     (queue->mmio_base == B43_MMIO_PIO1_BASE),
-			     "Frame FCS error");
-		return;
-	}
-	if (queue->mmio_base == B43_MMIO_PIO4_BASE) {
-		/* We received an xmit status. */
-		struct b43_hwtxstatus *hw;
-
-		hw = (struct b43_hwtxstatus *)(preamble + 1);
-		b43_handle_hwtxstatus(queue->dev, hw);
-
-		return;
-	}
-
-	skb = dev_alloc_skb(len);
-	if (unlikely(!skb)) {
-		pio_rx_error(queue, 1, "OOM");
-		return;
-	}
-	skb_put(skb, len);
-	for (i = 0; i < len - 1; i += 2) {
-		tmp = b43_pio_read(queue, B43_PIO_RXDATA);
-		*((__le16 *)(skb->data + i)) = cpu_to_le16(tmp);
-	}
-	if (len % 2) {
-		tmp = b43_pio_read(queue, B43_PIO_RXDATA);
-		skb->data[len - 1] = (tmp & 0x00FF);
-/* The specs say the following is required, but
- * it is wrong and corrupts the PLCP. If we don't do
- * this, the PLCP seems to be correct. So ifdef it out for now.
- */
-#if 0
-		if (rxflags2 & B43_RXHDR_FLAGS2_TYPE2FRAME)
-			skb->data[2] = (tmp & 0xFF00) >> 8;
-		else
-			skb->data[0] = (tmp & 0xFF00) >> 8;
-#endif
-	}
-	b43_rx(queue->dev, skb, rxhdr);
-}
-
-void b43_pio_tx_suspend(struct b43_pioqueue *queue)
-{
-	b43_power_saving_ctl_bits(queue->dev, B43_PS_AWAKE);
-	b43_pio_write(queue, B43_PIO_TXCTL, b43_pio_read(queue, B43_PIO_TXCTL)
-		      | B43_PIO_TXCTL_SUSPEND);
-}
-
-void b43_pio_tx_resume(struct b43_pioqueue *queue)
-{
-	b43_pio_write(queue, B43_PIO_TXCTL, b43_pio_read(queue, B43_PIO_TXCTL)
-		      & ~B43_PIO_TXCTL_SUSPEND);
-	b43_power_saving_ctl_bits(queue->dev, 0);
-	tasklet_schedule(&queue->txtask);
-}
-
-void b43_pio_freeze_txqueues(struct b43_wldev *dev)
-{
-	struct b43_pio *pio;
-
-	B43_WARN_ON(!b43_using_pio(dev));
-	pio = &dev->pio;
-	pio->queue0->tx_frozen = 1;
-	pio->queue1->tx_frozen = 1;
-	pio->queue2->tx_frozen = 1;
-	pio->queue3->tx_frozen = 1;
-}
-
-void b43_pio_thaw_txqueues(struct b43_wldev *dev)
-{
-	struct b43_pio *pio;
-
-	B43_WARN_ON(!b43_using_pio(dev));
-	pio = &dev->pio;
-	pio->queue0->tx_frozen = 0;
-	pio->queue1->tx_frozen = 0;
-	pio->queue2->tx_frozen = 0;
-	pio->queue3->tx_frozen = 0;
-	if (!list_empty(&pio->queue0->txqueue))
-		tasklet_schedule(&pio->queue0->txtask);
-	if (!list_empty(&pio->queue1->txqueue))
-		tasklet_schedule(&pio->queue1->txtask);
-	if (!list_empty(&pio->queue2->txqueue))
-		tasklet_schedule(&pio->queue2->txtask);
-	if (!list_empty(&pio->queue3->txqueue))
-		tasklet_schedule(&pio->queue3->txtask);
-}
diff --git a/package/b43/src/pio.h b/package/b43/src/pio.h
deleted file mode 100644
index 3488f2447b..0000000000
--- a/package/b43/src/pio.h
+++ /dev/null
@@ -1,153 +0,0 @@
-#ifndef B43_PIO_H_
-#define B43_PIO_H_
-
-#include "b43.h"
-
-#include <linux/interrupt.h>
-#include <linux/io.h>
-#include <linux/list.h>
-#include <linux/skbuff.h>
-
-#define B43_PIO_TXCTL		0x00
-#define B43_PIO_TXDATA		0x02
-#define B43_PIO_TXQBUFSIZE		0x04
-#define B43_PIO_RXCTL		0x08
-#define B43_PIO_RXDATA		0x0A
-
-#define B43_PIO_TXCTL_WRITELO	(1 << 0)
-#define B43_PIO_TXCTL_WRITEHI	(1 << 1)
-#define B43_PIO_TXCTL_COMPLETE	(1 << 2)
-#define B43_PIO_TXCTL_INIT		(1 << 3)
-#define B43_PIO_TXCTL_SUSPEND	(1 << 7)
-
-#define B43_PIO_RXCTL_DATAAVAILABLE	(1 << 0)
-#define B43_PIO_RXCTL_READY		(1 << 1)
-
-/* PIO constants */
-#define B43_PIO_MAXTXDEVQPACKETS	31
-#define B43_PIO_TXQADJUST		80
-
-/* PIO tuning knobs */
-#define B43_PIO_MAXTXPACKETS	256
-
-#ifdef CONFIG_B43_PIO
-
-struct b43_pioqueue;
-struct b43_xmitstatus;
-
-struct b43_pio_txpacket {
-	struct b43_pioqueue *queue;
-	struct sk_buff *skb;
-	struct ieee80211_tx_status txstat;
-	struct list_head list;
-	u16 index; /* Index in the tx_packets_cache */
-};
-
-struct b43_pioqueue {
-	struct b43_wldev *dev;
-	u16 mmio_base;
-
-	bool tx_suspended;
-	bool tx_frozen;
-	bool need_workarounds;	/* Workarounds needed for core.rev < 3 */
-
-	/* Adjusted size of the device internal TX buffer. */
-	u16 tx_devq_size;
-	/* Used octets of the device internal TX buffer. */
-	u16 tx_devq_used;
-	/* Used packet slots in the device internal TX buffer. */
-	u8 tx_devq_packets;
-	/* Packets from the txfree list can
-	 * be taken on incoming TX requests.
-	 */
-	struct list_head txfree;
-	unsigned int nr_txfree;
-	/* Packets on the txqueue are queued,
-	 * but not completely written to the chip, yet.
-	 */
-	struct list_head txqueue;
-	/* Packets on the txrunning queue are completely
-	 * posted to the device. We are waiting for the txstatus.
-	 */
-	struct list_head txrunning;
-	/* Total number or packets sent.
-	 * (This counter can obviously wrap).
-	 */
-	unsigned int nr_tx_packets;
-	struct tasklet_struct txtask;
-	struct b43_pio_txpacket tx_packets_cache[B43_PIO_MAXTXPACKETS];
-};
-
-static inline u16 b43_pio_read(struct b43_pioqueue *queue, u16 offset)
-{
-	return b43_read16(queue->dev, queue->mmio_base + offset);
-}
-
-static inline
-    void b43_pio_write(struct b43_pioqueue *queue, u16 offset, u16 value)
-{
-	b43_write16(queue->dev, queue->mmio_base + offset, value);
-	mmiowb();
-}
-
-int b43_pio_init(struct b43_wldev *dev);
-void b43_pio_free(struct b43_wldev *dev);
-
-int b43_pio_tx(struct b43_wldev *dev,
-	       struct sk_buff *skb, struct ieee80211_tx_control *ctl);
-void b43_pio_handle_txstatus(struct b43_wldev *dev,
-			     const struct b43_txstatus *status);
-void b43_pio_get_tx_stats(struct b43_wldev *dev,
-			  struct ieee80211_tx_queue_stats *stats);
-void b43_pio_rx(struct b43_pioqueue *queue);
-
-/* Suspend TX queue in hardware. */
-void b43_pio_tx_suspend(struct b43_pioqueue *queue);
-void b43_pio_tx_resume(struct b43_pioqueue *queue);
-/* Suspend (freeze) the TX tasklet (software level). */
-void b43_pio_freeze_txqueues(struct b43_wldev *dev);
-void b43_pio_thaw_txqueues(struct b43_wldev *dev);
-
-#else /* CONFIG_B43_PIO */
-
-static inline int b43_pio_init(struct b43_wldev *dev)
-{
-	return 0;
-}
-static inline void b43_pio_free(struct b43_wldev *dev)
-{
-}
-static inline
-    int b43_pio_tx(struct b43_wldev *dev,
-		   struct sk_buff *skb, struct ieee80211_tx_control *ctl)
-{
-	return 0;
-}
-static inline
-    void b43_pio_handle_txstatus(struct b43_wldev *dev,
-				 const struct b43_txstatus *status)
-{
-}
-static inline
-    void b43_pio_get_tx_stats(struct b43_wldev *dev,
-			      struct ieee80211_tx_queue_stats *stats)
-{
-}
-static inline void b43_pio_rx(struct b43_pioqueue *queue)
-{
-}
-static inline void b43_pio_tx_suspend(struct b43_pioqueue *queue)
-{
-}
-static inline void b43_pio_tx_resume(struct b43_pioqueue *queue)
-{
-}
-static inline void b43_pio_freeze_txqueues(struct b43_wldev *dev)
-{
-}
-static inline void b43_pio_thaw_txqueues(struct b43_wldev *dev)
-{
-}
-
-#endif /* CONFIG_B43_PIO */
-#endif /* B43_PIO_H_ */
diff --git a/package/b43/src/rfkill.c b/package/b43/src/rfkill.c
index 800e0a61a7..11f53cb113 100644
--- a/package/b43/src/rfkill.c
+++ b/package/b43/src/rfkill.c
@@ -25,6 +25,8 @@
 #include "rfkill.h"
 #include "b43.h"
 
+#include <linux/kmod.h>
+
 
 /* Returns TRUE, if the radio is enabled in hardware. */
 static bool b43_is_hw_radio_enabled(struct b43_wldev *dev)
@@ -47,32 +49,44 @@ static void b43_rfkill_poll(struct input_polled_dev *poll_dev)
 	struct b43_wldev *dev = poll_dev->private;
 	struct b43_wl *wl = dev->wl;
 	bool enabled;
+	bool report_change = 0;
 
 	mutex_lock(&wl->mutex);
-	B43_WARN_ON(b43_status(dev) < B43_STAT_INITIALIZED);
+	if (unlikely(b43_status(dev) < B43_STAT_INITIALIZED)) {
+		mutex_unlock(&wl->mutex);
+		return;
+	}
 	enabled = b43_is_hw_radio_enabled(dev);
 	if (unlikely(enabled != dev->radio_hw_enable)) {
 		dev->radio_hw_enable = enabled;
+		report_change = 1;
 		b43info(wl, "Radio hardware status changed to %s\n",
 			enabled ? "ENABLED" : "DISABLED");
-		mutex_unlock(&wl->mutex);
-		input_report_key(poll_dev->input, KEY_WLAN, enabled);
-	} else
-		mutex_unlock(&wl->mutex);
+	}
+	mutex_unlock(&wl->mutex);
+
+	/* send the radio switch event to the system - note both a key press
+	 * and a release are required */
+	if (unlikely(report_change)) {
+		input_report_key(poll_dev->input, KEY_WLAN, 1);
+		input_report_key(poll_dev->input, KEY_WLAN, 0);
+	}
 }
 
-/* Called when the RFKILL toggled in software.
- * This is called without locking. */
+/* Called when the RFKILL toggled in software. */
 static int b43_rfkill_soft_toggle(void *data, enum rfkill_state state)
 {
 	struct b43_wldev *dev = data;
 	struct b43_wl *wl = dev->wl;
-	int err = 0;
+	int err = -EBUSY;
+
+	if (!wl->rfkill.registered)
+		return 0;
 
 	mutex_lock(&wl->mutex);
 	if (b43_status(dev) < B43_STAT_INITIALIZED)
 		goto out_unlock;
-
+	err = 0;
 	switch (state) {
 	case RFKILL_STATE_ON:
 		if (!dev->radio_hw_enable) {
@@ -89,7 +103,6 @@ static int b43_rfkill_soft_toggle(void *data, enum rfkill_state state)
 			b43_radio_turn_off(dev, 0);
 		break;
 	}
-
 out_unlock:
 	mutex_unlock(&wl->mutex);
 
@@ -98,11 +111,11 @@ out_unlock:
 
 char * b43_rfkill_led_name(struct b43_wldev *dev)
 {
-	struct b43_wl *wl = dev->wl;
+	struct b43_rfkill *rfk = &(dev->wl->rfkill);
 
-	if (!wl->rfkill.rfkill)
+	if (!rfk->registered)
 		return NULL;
-	return rfkill_get_led_name(wl->rfkill.rfkill);
+	return rfkill_get_led_name(rfk->rfkill);
 }
 
 void b43_rfkill_init(struct b43_wldev *dev)
@@ -111,53 +124,13 @@ void b43_rfkill_init(struct b43_wldev *dev)
 	struct b43_rfkill *rfk = &(wl->rfkill);
 	int err;
 
-	if (rfk->rfkill) {
-		err = rfkill_register(rfk->rfkill);
-		if (err) {
-			b43warn(wl, "Failed to register RF-kill button\n");
-			goto err_free_rfk;
-		}
-	}
-	if (rfk->poll_dev) {
-		err = input_register_polled_device(rfk->poll_dev);
-		if (err) {
-			b43warn(wl, "Failed to register RF-kill polldev\n");
-			goto err_free_polldev;
-		}
-	}
-
-	return;
-err_free_rfk:
-	rfkill_free(rfk->rfkill);
-	rfk->rfkill = NULL;
-err_free_polldev:
-	input_free_polled_device(rfk->poll_dev);
-	rfk->poll_dev = NULL;
-}
-
-void b43_rfkill_exit(struct b43_wldev *dev)
-{
-	struct b43_rfkill *rfk = &(dev->wl->rfkill);
-
-	if (rfk->poll_dev)
-		input_unregister_polled_device(rfk->poll_dev);
-	if (rfk->rfkill)
-		rfkill_unregister(rfk->rfkill);
-}
-
-void b43_rfkill_alloc(struct b43_wldev *dev)
-{
-	struct b43_wl *wl = dev->wl;
-	struct b43_rfkill *rfk = &(wl->rfkill);
+	rfk->registered = 0;
 
+	rfk->rfkill = rfkill_allocate(dev->dev->dev, RFKILL_TYPE_WLAN);
+	if (!rfk->rfkill)
+		goto out_error;
 	snprintf(rfk->name, sizeof(rfk->name),
 		 "b43-%s", wiphy_name(wl->hw->wiphy));
-
-	rfk->rfkill = rfkill_allocate(dev->dev->dev, RFKILL_TYPE_WLAN);
-	if (!rfk->rfkill) {
-		b43warn(wl, "Failed to allocate RF-kill button\n");
-		return;
-	}
 	rfk->rfkill->name = rfk->name;
 	rfk->rfkill->state = RFKILL_STATE_ON;
 	rfk->rfkill->data = dev;
@@ -165,20 +138,64 @@ void b43_rfkill_alloc(struct b43_wldev *dev)
 	rfk->rfkill->user_claim_unsupported = 1;
 
 	rfk->poll_dev = input_allocate_polled_device();
-	if (rfk->poll_dev) {
-		rfk->poll_dev->private = dev;
-		rfk->poll_dev->poll = b43_rfkill_poll;
-		rfk->poll_dev->poll_interval = 1000; /* msecs */
-	} else
-		b43warn(wl, "Failed to allocate RF-kill polldev\n");
+	if (!rfk->poll_dev) {
+		rfkill_free(rfk->rfkill);
+		goto err_freed_rfk;
+	}
+
+	rfk->poll_dev->private = dev;
+	rfk->poll_dev->poll = b43_rfkill_poll;
+	rfk->poll_dev->poll_interval = 1000; /* msecs */
+
+	rfk->poll_dev->input->name = rfk->name;
+	rfk->poll_dev->input->id.bustype = BUS_HOST;
+	rfk->poll_dev->input->id.vendor = dev->dev->bus->boardinfo.vendor;
+	rfk->poll_dev->input->evbit[0] = BIT(EV_KEY);
+	set_bit(KEY_WLAN, rfk->poll_dev->input->keybit);
+
+	err = rfkill_register(rfk->rfkill);
+	if (err)
+		goto err_free_polldev;
+
+#ifdef CONFIG_RFKILL_INPUT_MODULE
+	/* B43 RF-kill isn't useful without the rfkill-input subsystem.
+	 * Try to load the module. */
+	err = request_module("rfkill-input");
+	if (err)
+		b43warn(wl, "Failed to load the rfkill-input module. "
+			"The built-in radio LED will not work.\n");
+#endif /* CONFIG_RFKILL_INPUT */
+
+	err = input_register_polled_device(rfk->poll_dev);
+	if (err)
+		goto err_unreg_rfk;
+
+	rfk->registered = 1;
+
+	return;
+err_unreg_rfk:
+	rfkill_unregister(rfk->rfkill);
+err_free_polldev:
+	input_free_polled_device(rfk->poll_dev);
+	rfk->poll_dev = NULL;
+err_freed_rfk:
+	rfk->rfkill = NULL;
+out_error:
+	rfk->registered = 0;
+	b43warn(wl, "RF-kill button init failed\n");
 }
 
-void b43_rfkill_free(struct b43_wldev *dev)
+void b43_rfkill_exit(struct b43_wldev *dev)
 {
 	struct b43_rfkill *rfk = &(dev->wl->rfkill);
 
+	if (!rfk->registered)
+		return;
+	rfk->registered = 0;
+
+	input_unregister_polled_device(rfk->poll_dev);
+	rfkill_unregister(rfk->rfkill);
 	input_free_polled_device(rfk->poll_dev);
 	rfk->poll_dev = NULL;
-	rfkill_free(rfk->rfkill);
 	rfk->rfkill = NULL;
 }
diff --git a/package/b43/src/rfkill.h b/package/b43/src/rfkill.h
index 29544e8c9e..adacf936d8 100644
--- a/package/b43/src/rfkill.h
+++ b/package/b43/src/rfkill.h
@@ -15,14 +15,14 @@ struct b43_rfkill {
 	struct rfkill *rfkill;
 	/* The poll device for the RFKILL input button */
 	struct input_polled_dev *poll_dev;
+	/* Did initialization succeed? Used for freeing. */
+	bool registered;
 	/* The unique name of this rfkill switch */
-	char name[32];
+	char name[sizeof("b43-phy4294967295")];
 };
 
-/* All the init functions return void, because we are not interested
+/* The init function returns void, because we are not interested
  * in failing the b43 init process when rfkill init failed. */
-void b43_rfkill_alloc(struct b43_wldev *dev);
-void b43_rfkill_free(struct b43_wldev *dev);
 void b43_rfkill_init(struct b43_wldev *dev);
 void b43_rfkill_exit(struct b43_wldev *dev);
 
@@ -36,12 +36,6 @@ struct b43_rfkill {
 	/* empty */
 };
 
-static inline void b43_rfkill_alloc(struct b43_wldev *dev)
-{
-}
-static inline void b43_rfkill_free(struct b43_wldev *dev)
-{
-}
 static inline void b43_rfkill_init(struct b43_wldev *dev)
 {
 }
diff --git a/package/b43/src/sysfs.c b/package/b43/src/sysfs.c
index f4faff6a7d..275095b8cb 100644
--- a/package/b43/src/sysfs.c
+++ b/package/b43/src/sysfs.c
@@ -47,29 +47,6 @@ static int get_integer(const char *buf, size_t count)
 	return ret;
 }
 
-static int get_boolean(const char *buf, size_t count)
-{
-	if (count != 0) {
-		if (buf[0] == '1')
-			return 1;
-		if (buf[0] == '0')
-			return 0;
-		if (count >= 4 && memcmp(buf, "true", 4) == 0)
-			return 1;
-		if (count >= 5 && memcmp(buf, "false", 5) == 0)
-			return 0;
-		if (count >= 3 && memcmp(buf, "yes", 3) == 0)
-			return 1;
-		if (count >= 2 && memcmp(buf, "no", 2) == 0)
-			return 0;
-		if (count >= 2 && memcmp(buf, "on", 2) == 0)
-			return 1;
-		if (count >= 3 && memcmp(buf, "off", 3) == 0)
-			return 0;
-	}
-	return -EINVAL;
-}
-
 static ssize_t b43_attr_interfmode_show(struct device *dev,
 					struct device_attribute *attr,
 					char *buf)
@@ -155,82 +132,18 @@ static ssize_t b43_attr_interfmode_store(struct device *dev,
 static DEVICE_ATTR(interference, 0644,
 		   b43_attr_interfmode_show, b43_attr_interfmode_store);
 
-static ssize_t b43_attr_preamble_show(struct device *dev,
-				      struct device_attribute *attr, char *buf)
-{
-	struct b43_wldev *wldev = dev_to_b43_wldev(dev);
-	ssize_t count;
-
-	if (!capable(CAP_NET_ADMIN))
-		return -EPERM;
-
-	mutex_lock(&wldev->wl->mutex);
-
-	if (wldev->short_preamble)
-		count =
-		    snprintf(buf, PAGE_SIZE, "1 (Short Preamble enabled)\n");
-	else
-		count =
-		    snprintf(buf, PAGE_SIZE, "0 (Short Preamble disabled)\n");
-
-	mutex_unlock(&wldev->wl->mutex);
-
-	return count;
-}
-
-static ssize_t b43_attr_preamble_store(struct device *dev,
-				       struct device_attribute *attr,
-				       const char *buf, size_t count)
-{
-	struct b43_wldev *wldev = dev_to_b43_wldev(dev);
-	unsigned long flags;
-	int value;
-
-	if (!capable(CAP_NET_ADMIN))
-		return -EPERM;
-
-	value = get_boolean(buf, count);
-	if (value < 0)
-		return value;
-	mutex_lock(&wldev->wl->mutex);
-	spin_lock_irqsave(&wldev->wl->irq_lock, flags);
-
-	wldev->short_preamble = !!value;
-
-	spin_unlock_irqrestore(&wldev->wl->irq_lock, flags);
-	mutex_unlock(&wldev->wl->mutex);
-
-	return count;
-}
-
-static DEVICE_ATTR(shortpreamble, 0644,
-		   b43_attr_preamble_show, b43_attr_preamble_store);
-
 int b43_sysfs_register(struct b43_wldev *wldev)
 {
 	struct device *dev = wldev->dev->dev;
-	int err;
 
 	B43_WARN_ON(b43_status(wldev) != B43_STAT_INITIALIZED);
 
-	err = device_create_file(dev, &dev_attr_interference);
-	if (err)
-		goto out;
-	err = device_create_file(dev, &dev_attr_shortpreamble);
-	if (err)
-		goto err_remove_interfmode;
-
-      out:
-	return err;
-      err_remove_interfmode:
-	device_remove_file(dev, &dev_attr_interference);
-	goto out;
+	return device_create_file(dev, &dev_attr_interference);
 }
 
 void b43_sysfs_unregister(struct b43_wldev *wldev)
 {
 	struct device *dev = wldev->dev->dev;
 
-	device_remove_file(dev, &dev_attr_shortpreamble);
 	device_remove_file(dev, &dev_attr_interference);
 }
diff --git a/package/b43/src/tables.c b/package/b43/src/tables.c
index 15a87183a5..3f5ea06bf1 100644
--- a/package/b43/src/tables.c
+++ b/package/b43/src/tables.c
@@ -3,7 +3,7 @@
   Broadcom B43 wireless driver
 
   Copyright (c) 2005 Martin Langer <martin-langer@gmx.de>,
-  Copyright (c) 2005 Stefano Brivio <st3@riseup.net>
+  Copyright (c) 2005-2007 Stefano Brivio <stefano.brivio@polimi.it>
   Copyright (c) 2006, 2006 Michael Buesch <mb@bu3sch.de>
   Copyright (c) 2005 Danny van Dyk <kugelfang@gentoo.org>
   Copyright (c) 2005 Andreas Jaggi <andreas.jaggi@waterwave.ch>
@@ -229,7 +229,7 @@ const u16 b43_tab_noisea2[] = {
 };
 
 const u16 b43_tab_noisea3[] = {
-	0x4C4C, 0x4C4C, 0x4C4C, 0x2D36,
+	0x5E5E, 0x5E5E, 0x5E5E, 0x3F48,
 	0x4C4C, 0x4C4C, 0x4C4C, 0x2D36,
 };
 
@@ -243,6 +243,26 @@ const u16 b43_tab_noiseg2[] = {
 	0x0000, 0x0000, 0x0000, 0x0000,
 };
 
+const u16 b43_tab_noisescalea2[] = {
+	0x6767, 0x6767, 0x6767, 0x6767, /* 0 */
+	0x6767, 0x6767, 0x6767, 0x6767,
+	0x6767, 0x6767, 0x6767, 0x6767,
+	0x6767, 0x6700, 0x6767, 0x6767,
+	0x6767, 0x6767, 0x6767, 0x6767, /* 16 */
+	0x6767, 0x6767, 0x6767, 0x6767,
+	0x6767, 0x6767, 0x0067,
+};
+
+const u16 b43_tab_noisescalea3[] = {
+	0x2323, 0x2323, 0x2323, 0x2323, /* 0 */
+	0x2323, 0x2323, 0x2323, 0x2323,
+	0x2323, 0x2323, 0x2323, 0x2323,
+	0x2323, 0x2300, 0x2323, 0x2323,
+	0x2323, 0x2323, 0x2323, 0x2323, /* 16 */
+	0x2323, 0x2323, 0x2323, 0x2323,
+	0x2323, 0x2323, 0x0023,
+};
+
 const u16 b43_tab_noisescaleg1[] = {
 	0x6C77, 0x5162, 0x3B40, 0x3335,	/* 0 */
 	0x2F2D, 0x2A2A, 0x2527, 0x1F21,
@@ -254,7 +274,7 @@ const u16 b43_tab_noisescaleg1[] = {
 };
 
 const u16 b43_tab_noisescaleg2[] = {
-	0xD8DD, 0xCBD4, 0xBCC0, 0XB6B7,	/* 0 */
+	0xD8DD, 0xCBD4, 0xBCC0, 0xB6B7,	/* 0 */
 	0xB2B0, 0xADAD, 0xA7A9, 0x9FA1,
 	0x969B, 0x9195, 0x8F8F, 0x8A8A,
 	0x8A8A, 0x8A00, 0x8A8A, 0x8F8A,
@@ -307,6 +327,28 @@ const u16 b43_tab_sigmasqr2[] = {
 	0x00DE,
 };
 
+const u16 b43_tab_rssiagc1[] = {
+	0xFFF8, 0xFFF8, 0xFFF8, 0xFFF8, /* 0 */
+	0xFFF8, 0xFFF9, 0xFFFC, 0xFFFE,
+	0xFFF8, 0xFFF8, 0xFFF8, 0xFFF8,
+	0xFFF8, 0xFFF8, 0xFFF8, 0xFFF8,
+};
+
+const u16 b43_tab_rssiagc2[] = {
+	0x0820, 0x0820, 0x0920, 0x0C38, /* 0 */
+	0x0820, 0x0820, 0x0820, 0x0820,
+	0x0820, 0x0820, 0x0920, 0x0A38,
+	0x0820, 0x0820, 0x0820, 0x0820,
+	0x0820, 0x0820, 0x0920, 0x0A38, /* 16 */
+	0x0820, 0x0820, 0x0820, 0x0820,
+	0x0820, 0x0820, 0x0920, 0x0A38,
+	0x0820, 0x0820, 0x0820, 0x0820,
+	0x0820, 0x0820, 0x0920, 0x0A38, /* 32 */
+	0x0820, 0x0820, 0x0820, 0x0820,
+	0x0820, 0x0820, 0x0920, 0x0A38,
+	0x0820, 0x0820, 0x0820, 0x0820,
+};
+
 static inline void assert_sizes(void)
 {
 	BUILD_BUG_ON(B43_TAB_ROTOR_SIZE != ARRAY_SIZE(b43_tab_rotor));
@@ -317,36 +359,73 @@ static inline void assert_sizes(void)
 	BUILD_BUG_ON(B43_TAB_NOISEA3_SIZE != ARRAY_SIZE(b43_tab_noisea3));
 	BUILD_BUG_ON(B43_TAB_NOISEG1_SIZE != ARRAY_SIZE(b43_tab_noiseg1));
 	BUILD_BUG_ON(B43_TAB_NOISEG2_SIZE != ARRAY_SIZE(b43_tab_noiseg2));
-	BUILD_BUG_ON(B43_TAB_NOISESCALEG_SIZE !=
+	BUILD_BUG_ON(B43_TAB_NOISESCALE_SIZE !=
+		     ARRAY_SIZE(b43_tab_noisescalea2));
+	BUILD_BUG_ON(B43_TAB_NOISESCALE_SIZE !=
+		     ARRAY_SIZE(b43_tab_noisescalea3));
+	BUILD_BUG_ON(B43_TAB_NOISESCALE_SIZE !=
 		     ARRAY_SIZE(b43_tab_noisescaleg1));
-	BUILD_BUG_ON(B43_TAB_NOISESCALEG_SIZE !=
+	BUILD_BUG_ON(B43_TAB_NOISESCALE_SIZE !=
 		     ARRAY_SIZE(b43_tab_noisescaleg2));
-	BUILD_BUG_ON(B43_TAB_NOISESCALEG_SIZE !=
+	BUILD_BUG_ON(B43_TAB_NOISESCALE_SIZE !=
 		     ARRAY_SIZE(b43_tab_noisescaleg3));
 	BUILD_BUG_ON(B43_TAB_SIGMASQR_SIZE != ARRAY_SIZE(b43_tab_sigmasqr1));
 	BUILD_BUG_ON(B43_TAB_SIGMASQR_SIZE != ARRAY_SIZE(b43_tab_sigmasqr2));
+	BUILD_BUG_ON(B43_TAB_RSSIAGC1_SIZE != ARRAY_SIZE(b43_tab_rssiagc1));
+	BUILD_BUG_ON(B43_TAB_RSSIAGC2_SIZE != ARRAY_SIZE(b43_tab_rssiagc2));
 }
 
 u16 b43_ofdmtab_read16(struct b43_wldev *dev, u16 table, u16 offset)
 {
-	assert_sizes();
+	struct b43_phy *phy = &dev->phy;
+	u16 addr;
+
+	addr = table + offset;
+	if ((phy->ofdmtab_addr_direction != B43_OFDMTAB_DIRECTION_READ) ||
+	    (addr - 1 != phy->ofdmtab_addr)) {
+		/* The hardware has a different address in memory. Update it. */
+		b43_phy_write(dev, B43_PHY_OTABLECTL, addr);
+		phy->ofdmtab_addr_direction = B43_OFDMTAB_DIRECTION_READ;
+	}
+	phy->ofdmtab_addr = addr;
 
-	b43_phy_write(dev, B43_PHY_OTABLECTL, table + offset);
 	return b43_phy_read(dev, B43_PHY_OTABLEI);
+
+	/* Some compiletime assertions... */
+	assert_sizes();
 }
 
 void b43_ofdmtab_write16(struct b43_wldev *dev, u16 table,
 			 u16 offset, u16 value)
 {
-	b43_phy_write(dev, B43_PHY_OTABLECTL, table + offset);
+	struct b43_phy *phy = &dev->phy;
+	u16 addr;
+
+	addr = table + offset;
+	if ((phy->ofdmtab_addr_direction != B43_OFDMTAB_DIRECTION_WRITE) ||
+	    (addr - 1 != phy->ofdmtab_addr)) {
+		/* The hardware has a different address in memory. Update it. */
+		b43_phy_write(dev, B43_PHY_OTABLECTL, addr);
+		phy->ofdmtab_addr_direction = B43_OFDMTAB_DIRECTION_WRITE;
+	}
+	phy->ofdmtab_addr = addr;
 	b43_phy_write(dev, B43_PHY_OTABLEI, value);
 }
 
 u32 b43_ofdmtab_read32(struct b43_wldev *dev, u16 table, u16 offset)
 {
+	struct b43_phy *phy = &dev->phy;
 	u32 ret;
+	u16 addr;
 
-	b43_phy_write(dev, B43_PHY_OTABLECTL, table + offset);
+	addr = table + offset;
+	if ((phy->ofdmtab_addr_direction != B43_OFDMTAB_DIRECTION_READ) ||
+	    (addr - 1 != phy->ofdmtab_addr)) {
+		/* The hardware has a different address in memory. Update it. */
+		b43_phy_write(dev, B43_PHY_OTABLECTL, addr);
+		phy->ofdmtab_addr_direction = B43_OFDMTAB_DIRECTION_READ;
+	}
+	phy->ofdmtab_addr = addr;
 	ret = b43_phy_read(dev, B43_PHY_OTABLEQ);
 	ret <<= 16;
 	ret |= b43_phy_read(dev, B43_PHY_OTABLEI);
@@ -357,7 +436,18 @@ u32 b43_ofdmtab_read32(struct b43_wldev *dev, u16 table, u16 offset)
 void b43_ofdmtab_write32(struct b43_wldev *dev, u16 table,
 			 u16 offset, u32 value)
 {
-	b43_phy_write(dev, B43_PHY_OTABLECTL, table + offset);
+	struct b43_phy *phy = &dev->phy;
+	u16 addr;
+
+	addr = table + offset;
+	if ((phy->ofdmtab_addr_direction != B43_OFDMTAB_DIRECTION_WRITE) ||
+	    (addr - 1 != phy->ofdmtab_addr)) {
+		/* The hardware has a different address in memory. Update it. */
+		b43_phy_write(dev, B43_PHY_OTABLECTL, addr);
+		phy->ofdmtab_addr_direction = B43_OFDMTAB_DIRECTION_WRITE;
+	}
+	phy->ofdmtab_addr = addr;
+
 	b43_phy_write(dev, B43_PHY_OTABLEI, value);
 	b43_phy_write(dev, B43_PHY_OTABLEQ, (value >> 16));
 }
diff --git a/package/b43/src/tables.h b/package/b43/src/tables.h
index 64635d7b51..80e73c7cba 100644
--- a/package/b43/src/tables.h
+++ b/package/b43/src/tables.h
@@ -1,9 +1,9 @@
 #ifndef B43_TABLES_H_
 #define B43_TABLES_H_
 
-#define B43_TAB_ROTOR_SIZE		53
+#define B43_TAB_ROTOR_SIZE	53
 extern const u32 b43_tab_rotor[];
-#define B43_TAB_RETARD_SIZE		53
+#define B43_TAB_RETARD_SIZE	53
 extern const u32 b43_tab_retard[];
 #define B43_TAB_FINEFREQA_SIZE	256
 extern const u16 b43_tab_finefreqa[];
@@ -17,12 +17,18 @@ extern const u16 b43_tab_noisea3[];
 extern const u16 b43_tab_noiseg1[];
 #define B43_TAB_NOISEG2_SIZE	8
 extern const u16 b43_tab_noiseg2[];
-#define B43_TAB_NOISESCALEG_SIZE	27
+#define B43_TAB_NOISESCALE_SIZE	27
+extern const u16 b43_tab_noisescalea2[];
+extern const u16 b43_tab_noisescalea3[];
 extern const u16 b43_tab_noisescaleg1[];
 extern const u16 b43_tab_noisescaleg2[];
 extern const u16 b43_tab_noisescaleg3[];
 #define B43_TAB_SIGMASQR_SIZE	53
 extern const u16 b43_tab_sigmasqr1[];
 extern const u16 b43_tab_sigmasqr2[];
+#define B43_TAB_RSSIAGC1_SIZE	16
+extern const u16 b43_tab_rssiagc1[];
+#define B43_TAB_RSSIAGC2_SIZE	48
+extern const u16 b43_tab_rssiagc2[];
 
 #endif /* B43_TABLES_H_ */
diff --git a/package/b43/src/tables_nphy.c b/package/b43/src/tables_nphy.c
new file mode 100644
index 0000000000..2aa5755178
--- /dev/null
+++ b/package/b43/src/tables_nphy.c
@@ -0,0 +1,2476 @@
+/*
+
+  Broadcom B43 wireless driver
+  IEEE 802.11n PHY and radio device data tables
+
+  Copyright (c) 2008 Michael Buesch <mb@bu3sch.de>
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 of the License, or
+  (at your option) any later version.
+
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program; see the file COPYING.  If not, write to
+  the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
+  Boston, MA 02110-1301, USA.
+
+*/
+
+#include "b43.h"
+#include "tables_nphy.h"
+#include "phy.h"
+#include "nphy.h"
+
+
+struct b2055_inittab_entry {
+	/* Value to write if we use the 5GHz band. */
+	u16 ghz5;
+	/* Value to write if we use the 2.4GHz band. */
+	u16 ghz2;
+	/* Flags */
+	u8 flags;
+#define B2055_INITTAB_ENTRY_OK	0x01
+#define B2055_INITTAB_UPLOAD	0x02
+};
+#define UPLOAD		.flags = B2055_INITTAB_ENTRY_OK | B2055_INITTAB_UPLOAD
+#define NOUPLOAD	.flags = B2055_INITTAB_ENTRY_OK
+
+static const struct b2055_inittab_entry b2055_inittab [] = {
+  [B2055_SP_PINPD]		= { .ghz5 = 0x0080, .ghz2 = 0x0080, NOUPLOAD, },
+  [B2055_C1_SP_RSSI]		= { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+  [B2055_C1_SP_PDMISC]		= { .ghz5 = 0x0027, .ghz2 = 0x0027, NOUPLOAD, },
+  [B2055_C2_SP_RSSI]		= { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+  [B2055_C2_SP_PDMISC]		= { .ghz5 = 0x0027, .ghz2 = 0x0027, NOUPLOAD, },
+  [B2055_C1_SP_RXGC1]		= { .ghz5 = 0x007F, .ghz2 = 0x007F, UPLOAD, },
+  [B2055_C1_SP_RXGC2]		= { .ghz5 = 0x0007, .ghz2 = 0x0007, UPLOAD, },
+  [B2055_C2_SP_RXGC1]		= { .ghz5 = 0x007F, .ghz2 = 0x007F, UPLOAD, },
+  [B2055_C2_SP_RXGC2]		= { .ghz5 = 0x0007, .ghz2 = 0x0007, UPLOAD, },
+  [B2055_C1_SP_LPFBWSEL]	= { .ghz5 = 0x0015, .ghz2 = 0x0015, NOUPLOAD, },
+  [B2055_C2_SP_LPFBWSEL]	= { .ghz5 = 0x0015, .ghz2 = 0x0015, NOUPLOAD, },
+  [B2055_C1_SP_TXGC1]		= { .ghz5 = 0x004F, .ghz2 = 0x004F, UPLOAD, },
+  [B2055_C1_SP_TXGC2]		= { .ghz5 = 0x0005, .ghz2 = 0x0005, UPLOAD, },
+  [B2055_C2_SP_TXGC1]		= { .ghz5 = 0x004F, .ghz2 = 0x004F, UPLOAD, },
+  [B2055_C2_SP_TXGC2]		= { .ghz5 = 0x0005, .ghz2 = 0x0005, UPLOAD, },
+  [B2055_MASTER1]		= { .ghz5 = 0x00D0, .ghz2 = 0x00D0, NOUPLOAD, },
+  [B2055_MASTER2]		= { .ghz5 = 0x0002, .ghz2 = 0x0002, NOUPLOAD, },
+  [B2055_PD_LGEN]		= { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+  [B2055_PD_PLLTS]		= { .ghz5 = 0x0040, .ghz2 = 0x0040, NOUPLOAD, },
+  [B2055_C1_PD_LGBUF]		= { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+  [B2055_C1_PD_TX]		= { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+  [B2055_C1_PD_RXTX]		= { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+  [B2055_C1_PD_RSSIMISC]	= { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+  [B2055_C2_PD_LGBUF]		= { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+  [B2055_C2_PD_TX]		= { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+  [B2055_C2_PD_RXTX]		= { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+  [B2055_C2_PD_RSSIMISC]	= { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+  [B2055_PWRDET_LGEN]		= { .ghz5 = 0x00C0, .ghz2 = 0x00C0, NOUPLOAD, },
+  [B2055_C1_PWRDET_LGBUF]	= { .ghz5 = 0x00FF, .ghz2 = 0x00FF, NOUPLOAD, },
+  [B2055_C1_PWRDET_RXTX]	= { .ghz5 = 0x00C0, .ghz2 = 0x00C0, NOUPLOAD, },
+  [B2055_C2_PWRDET_LGBUF]	= { .ghz5 = 0x00FF, .ghz2 = 0x00FF, NOUPLOAD, },
+  [B2055_C2_PWRDET_RXTX]	= { .ghz5 = 0x00C0, .ghz2 = 0x00C0, NOUPLOAD, },
+  [B2055_RRCCAL_CS]		= { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+  [B2055_RRCCAL_NOPTSEL]	= { .ghz5 = 0x002C, .ghz2 = 0x002C, NOUPLOAD, },
+  [B2055_CAL_MISC]		= { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+  [B2055_CAL_COUT]		= { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+  [B2055_CAL_COUT2]		= { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+  [B2055_CAL_CVARCTL]		= { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+  [B2055_CAL_RVARCTL]		= { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+  [B2055_CAL_LPOCTL]		= { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+  [B2055_CAL_TS]		= { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+  [B2055_CAL_RCCALRTS]		= { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+  [B2055_CAL_RCALRTS]		= { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+  [B2055_PADDRV]		= { .ghz5 = 0x00A4, .ghz2 = 0x00A4, NOUPLOAD, },
+  [B2055_XOCTL1]		= { .ghz5 = 0x0038, .ghz2 = 0x0038, NOUPLOAD, },
+  [B2055_XOCTL2]		= { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+  [B2055_XOREGUL]		= { .ghz5 = 0x0004, .ghz2 = 0x0004, UPLOAD, },
+  [B2055_XOMISC]		= { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+  [B2055_PLL_LFC1]		= { .ghz5 = 0x000A, .ghz2 = 0x000A, NOUPLOAD, },
+  [B2055_PLL_CALVTH]		= { .ghz5 = 0x0087, .ghz2 = 0x0087, NOUPLOAD, },
+  [B2055_PLL_LFC2]		= { .ghz5 = 0x0009, .ghz2 = 0x0009, NOUPLOAD, },
+  [B2055_PLL_REF]		= { .ghz5 = 0x0070, .ghz2 = 0x0070, NOUPLOAD, },
+  [B2055_PLL_LFR1]		= { .ghz5 = 0x0011, .ghz2 = 0x0011, NOUPLOAD, },
+  [B2055_PLL_PFDCP]		= { .ghz5 = 0x0018, .ghz2 = 0x0018, UPLOAD, },
+  [B2055_PLL_IDAC_CPOPAMP]	= { .ghz5 = 0x0006, .ghz2 = 0x0006, NOUPLOAD, },
+  [B2055_PLL_CPREG]		= { .ghz5 = 0x0004, .ghz2 = 0x0004, UPLOAD, },
+  [B2055_PLL_RCAL]		= { .ghz5 = 0x0006, .ghz2 = 0x0006, NOUPLOAD, },
+  [B2055_RF_PLLMOD0]		= { .ghz5 = 0x009E, .ghz2 = 0x009E, NOUPLOAD, },
+  [B2055_RF_PLLMOD1]		= { .ghz5 = 0x0009, .ghz2 = 0x0009, NOUPLOAD, },
+  [B2055_RF_MMDIDAC1]		= { .ghz5 = 0x00C8, .ghz2 = 0x00C8, UPLOAD, },
+  [B2055_RF_MMDIDAC0]		= { .ghz5 = 0x0088, .ghz2 = 0x0088, NOUPLOAD, },
+  [B2055_RF_MMDSP]		= { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+  [B2055_VCO_CAL1]		= { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+  [B2055_VCO_CAL2]		= { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+  [B2055_VCO_CAL3]		= { .ghz5 = 0x0001, .ghz2 = 0x0001, NOUPLOAD, },
+  [B2055_VCO_CAL4]		= { .ghz5 = 0x0002, .ghz2 = 0x0002, NOUPLOAD, },
+  [B2055_VCO_CAL5]		= { .ghz5 = 0x0096, .ghz2 = 0x0096, NOUPLOAD, },
+  [B2055_VCO_CAL6]		= { .ghz5 = 0x003E, .ghz2 = 0x003E, NOUPLOAD, },
+  [B2055_VCO_CAL7]		= { .ghz5 = 0x003E, .ghz2 = 0x003E, NOUPLOAD, },
+  [B2055_VCO_CAL8]		= { .ghz5 = 0x0013, .ghz2 = 0x0013, NOUPLOAD, },
+  [B2055_VCO_CAL9]		= { .ghz5 = 0x0002, .ghz2 = 0x0002, NOUPLOAD, },
+  [B2055_VCO_CAL10]		= { .ghz5 = 0x0015, .ghz2 = 0x0015, NOUPLOAD, },
+  [B2055_VCO_CAL11]		= { .ghz5 = 0x0007, .ghz2 = 0x0007, NOUPLOAD, },
+  [B2055_VCO_CAL12]		= { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+  [B2055_VCO_CAL13]		= { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+  [B2055_VCO_CAL14]		= { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+  [B2055_VCO_CAL15]		= { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+  [B2055_VCO_CAL16]		= { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+  [B2055_VCO_KVCO]		= { .ghz5 = 0x0008, .ghz2 = 0x0008, NOUPLOAD, },
+  [B2055_VCO_CAPTAIL]		= { .ghz5 = 0x0008, .ghz2 = 0x0008, NOUPLOAD, },
+  [B2055_VCO_IDACVCO]		= { .ghz5 = 0x0006, .ghz2 = 0x0006, NOUPLOAD, },
+  [B2055_VCO_REG]		= { .ghz5 = 0x0084, .ghz2 = 0x0084, UPLOAD, },
+  [B2055_PLL_RFVTH]		= { .ghz5 = 0x00C3, .ghz2 = 0x00C3, NOUPLOAD, },
+  [B2055_LGBUF_CENBUF]		= { .ghz5 = 0x008F, .ghz2 = 0x008F, NOUPLOAD, },
+  [B2055_LGEN_TUNE1]		= { .ghz5 = 0x00FF, .ghz2 = 0x00FF, NOUPLOAD, },
+  [B2055_LGEN_TUNE2]		= { .ghz5 = 0x00FF, .ghz2 = 0x00FF, NOUPLOAD, },
+  [B2055_LGEN_IDAC1]		= { .ghz5 = 0x0088, .ghz2 = 0x0088, NOUPLOAD, },
+  [B2055_LGEN_IDAC2]		= { .ghz5 = 0x0088, .ghz2 = 0x0088, NOUPLOAD, },
+  [B2055_LGEN_BIASC]		= { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+  [B2055_LGEN_BIASIDAC]		= { .ghz5 = 0x00CC, .ghz2 = 0x00CC, NOUPLOAD, },
+  [B2055_LGEN_RCAL]		= { .ghz5 = 0x0006, .ghz2 = 0x0006, NOUPLOAD, },
+  [B2055_LGEN_DIV]		= { .ghz5 = 0x0080, .ghz2 = 0x0080, NOUPLOAD, },
+  [B2055_LGEN_SPARE2]		= { .ghz5 = 0x0080, .ghz2 = 0x0080, NOUPLOAD, },
+  [B2055_C1_LGBUF_ATUNE]	= { .ghz5 = 0x00F8, .ghz2 = 0x00F8, NOUPLOAD, },
+  [B2055_C1_LGBUF_GTUNE]	= { .ghz5 = 0x0088, .ghz2 = 0x0088, NOUPLOAD, },
+  [B2055_C1_LGBUF_DIV]		= { .ghz5 = 0x0088, .ghz2 = 0x0088, NOUPLOAD, },
+  [B2055_C1_LGBUF_AIDAC]	= { .ghz5 = 0x0088, .ghz2 = 0x0008, UPLOAD, },
+  [B2055_C1_LGBUF_GIDAC]	= { .ghz5 = 0x0088, .ghz2 = 0x0088, NOUPLOAD, },
+  [B2055_C1_LGBUF_IDACFO]	= { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+  [B2055_C1_LGBUF_SPARE]	= { .ghz5 = 0x0001, .ghz2 = 0x0001, UPLOAD, },
+  [B2055_C1_RX_RFSPC1]		= { .ghz5 = 0x008A, .ghz2 = 0x008A, NOUPLOAD, },
+  [B2055_C1_RX_RFR1]		= { .ghz5 = 0x0008, .ghz2 = 0x0008, NOUPLOAD, },
+  [B2055_C1_RX_RFR2]		= { .ghz5 = 0x0083, .ghz2 = 0x0083, NOUPLOAD, },
+  [B2055_C1_RX_RFRCAL]		= { .ghz5 = 0x0006, .ghz2 = 0x0006, NOUPLOAD, },
+  [B2055_C1_RX_BB_BLCMP]	= { .ghz5 = 0x00A0, .ghz2 = 0x00A0, NOUPLOAD, },
+  [B2055_C1_RX_BB_LPF]		= { .ghz5 = 0x000A, .ghz2 = 0x000A, NOUPLOAD, },
+  [B2055_C1_RX_BB_MIDACHP]	= { .ghz5 = 0x0087, .ghz2 = 0x0087, UPLOAD, },
+  [B2055_C1_RX_BB_VGA1IDAC]	= { .ghz5 = 0x002A, .ghz2 = 0x002A, NOUPLOAD, },
+  [B2055_C1_RX_BB_VGA2IDAC]	= { .ghz5 = 0x002A, .ghz2 = 0x002A, NOUPLOAD, },
+  [B2055_C1_RX_BB_VGA3IDAC]	= { .ghz5 = 0x002A, .ghz2 = 0x002A, NOUPLOAD, },
+  [B2055_C1_RX_BB_BUFOCTL]	= { .ghz5 = 0x002A, .ghz2 = 0x002A, NOUPLOAD, },
+  [B2055_C1_RX_BB_RCCALCTL]	= { .ghz5 = 0x0018, .ghz2 = 0x0018, NOUPLOAD, },
+  [B2055_C1_RX_BB_RSSICTL1]	= { .ghz5 = 0x006A, .ghz2 = 0x006A, UPLOAD, },
+  [B2055_C1_RX_BB_RSSICTL2]	= { .ghz5 = 0x00AB, .ghz2 = 0x00AB, UPLOAD, },
+  [B2055_C1_RX_BB_RSSICTL3]	= { .ghz5 = 0x0013, .ghz2 = 0x0013, UPLOAD, },
+  [B2055_C1_RX_BB_RSSICTL4]	= { .ghz5 = 0x00C1, .ghz2 = 0x00C1, UPLOAD, },
+  [B2055_C1_RX_BB_RSSICTL5]	= { .ghz5 = 0x00AA, .ghz2 = 0x00AA, UPLOAD, },
+  [B2055_C1_RX_BB_REG]		= { .ghz5 = 0x0087, .ghz2 = 0x0087, UPLOAD, },
+  [B2055_C1_RX_BB_SPARE1]	= { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+  [B2055_C1_RX_TXBBRCAL]	= { .ghz5 = 0x0006, .ghz2 = 0x0006, NOUPLOAD, },
+  [B2055_C1_TX_RF_SPGA]		= { .ghz5 = 0x0007, .ghz2 = 0x0007, NOUPLOAD, },
+  [B2055_C1_TX_RF_SPAD]		= { .ghz5 = 0x0007, .ghz2 = 0x0007, NOUPLOAD, },
+  [B2055_C1_TX_RF_CNTPGA1]	= { .ghz5 = 0x0015, .ghz2 = 0x0015, NOUPLOAD, },
+  [B2055_C1_TX_RF_CNTPAD1]	= { .ghz5 = 0x0055, .ghz2 = 0x0055, NOUPLOAD, },
+  [B2055_C1_TX_RF_PGAIDAC]	= { .ghz5 = 0x0097, .ghz2 = 0x0097, UPLOAD, },
+  [B2055_C1_TX_PGAPADTN]	= { .ghz5 = 0x0008, .ghz2 = 0x0008, NOUPLOAD, },
+  [B2055_C1_TX_PADIDAC1]	= { .ghz5 = 0x0014, .ghz2 = 0x0014, UPLOAD, },
+  [B2055_C1_TX_PADIDAC2]	= { .ghz5 = 0x0033, .ghz2 = 0x0033, NOUPLOAD, },
+  [B2055_C1_TX_MXBGTRIM]	= { .ghz5 = 0x0088, .ghz2 = 0x0088, NOUPLOAD, },
+  [B2055_C1_TX_RF_RCAL]		= { .ghz5 = 0x0006, .ghz2 = 0x0006, NOUPLOAD, },
+  [B2055_C1_TX_RF_PADTSSI1]	= { .ghz5 = 0x0003, .ghz2 = 0x0003, UPLOAD, },
+  [B2055_C1_TX_RF_PADTSSI2]	= { .ghz5 = 0x000A, .ghz2 = 0x000A, NOUPLOAD, },
+  [B2055_C1_TX_RF_SPARE]	= { .ghz5 = 0x0003, .ghz2 = 0x0003, UPLOAD, },
+  [B2055_C1_TX_RF_IQCAL1]	= { .ghz5 = 0x002A, .ghz2 = 0x002A, NOUPLOAD, },
+  [B2055_C1_TX_RF_IQCAL2]	= { .ghz5 = 0x00A4, .ghz2 = 0x00A4, NOUPLOAD, },
+  [B2055_C1_TXBB_RCCAL]		= { .ghz5 = 0x0018, .ghz2 = 0x0018, NOUPLOAD, },
+  [B2055_C1_TXBB_LPF1]		= { .ghz5 = 0x0028, .ghz2 = 0x0028, NOUPLOAD, },
+  [B2055_C1_TX_VOSCNCL]		= { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+  [B2055_C1_TX_LPF_MXGMIDAC]	= { .ghz5 = 0x004A, .ghz2 = 0x004A, NOUPLOAD, },
+  [B2055_C1_TX_BB_MXGM]		= { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+  [B2055_C2_LGBUF_ATUNE]	= { .ghz5 = 0x00F8, .ghz2 = 0x00F8, NOUPLOAD, },
+  [B2055_C2_LGBUF_GTUNE]	= { .ghz5 = 0x0088, .ghz2 = 0x0088, NOUPLOAD, },
+  [B2055_C2_LGBUF_DIV]		= { .ghz5 = 0x0088, .ghz2 = 0x0088, NOUPLOAD, },
+  [B2055_C2_LGBUF_AIDAC]	= { .ghz5 = 0x0088, .ghz2 = 0x0008, UPLOAD, },
+  [B2055_C2_LGBUF_GIDAC]	= { .ghz5 = 0x0088, .ghz2 = 0x0088, NOUPLOAD, },
+  [B2055_C2_LGBUF_IDACFO]	= { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+  [B2055_C2_LGBUF_SPARE]	= { .ghz5 = 0x0001, .ghz2 = 0x0001, UPLOAD, },
+  [B2055_C2_RX_RFSPC1]		= { .ghz5 = 0x008A, .ghz2 = 0x008A, NOUPLOAD, },
+  [B2055_C2_RX_RFR1]		= { .ghz5 = 0x0008, .ghz2 = 0x0008, NOUPLOAD, },
+  [B2055_C2_RX_RFR2]		= { .ghz5 = 0x0083, .ghz2 = 0x0083, NOUPLOAD, },
+  [B2055_C2_RX_RFRCAL]		= { .ghz5 = 0x0006, .ghz2 = 0x0006, NOUPLOAD, },
+  [B2055_C2_RX_BB_BLCMP]	= { .ghz5 = 0x00A0, .ghz2 = 0x00A0, NOUPLOAD, },
+  [B2055_C2_RX_BB_LPF]		= { .ghz5 = 0x000A, .ghz2 = 0x000A, NOUPLOAD, },
+  [B2055_C2_RX_BB_MIDACHP]	= { .ghz5 = 0x0087, .ghz2 = 0x0087, UPLOAD, },
+  [B2055_C2_RX_BB_VGA1IDAC]	= { .ghz5 = 0x002A, .ghz2 = 0x002A, NOUPLOAD, },
+  [B2055_C2_RX_BB_VGA2IDAC]	= { .ghz5 = 0x002A, .ghz2 = 0x002A, NOUPLOAD, },
+  [B2055_C2_RX_BB_VGA3IDAC]	= { .ghz5 = 0x002A, .ghz2 = 0x002A, NOUPLOAD, },
+  [B2055_C2_RX_BB_BUFOCTL]	= { .ghz5 = 0x002A, .ghz2 = 0x002A, NOUPLOAD, },
+  [B2055_C2_RX_BB_RCCALCTL]	= { .ghz5 = 0x0018, .ghz2 = 0x0018, NOUPLOAD, },
+  [B2055_C2_RX_BB_RSSICTL1]	= { .ghz5 = 0x006A, .ghz2 = 0x006A, UPLOAD, },
+  [B2055_C2_RX_BB_RSSICTL2]	= { .ghz5 = 0x00AB, .ghz2 = 0x00AB, UPLOAD, },
+  [B2055_C2_RX_BB_RSSICTL3]	= { .ghz5 = 0x0013, .ghz2 = 0x0013, UPLOAD, },
+  [B2055_C2_RX_BB_RSSICTL4]	= { .ghz5 = 0x00C1, .ghz2 = 0x00C1, UPLOAD, },
+  [B2055_C2_RX_BB_RSSICTL5]	= { .ghz5 = 0x00AA, .ghz2 = 0x00AA, UPLOAD, },
+  [B2055_C2_RX_BB_REG]		= { .ghz5 = 0x0087, .ghz2 = 0x0087, UPLOAD, },
+  [B2055_C2_RX_BB_SPARE1]	= { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+  [B2055_C2_RX_TXBBRCAL]	= { .ghz5 = 0x0006, .ghz2 = 0x0006, NOUPLOAD, },
+  [B2055_C2_TX_RF_SPGA]		= { .ghz5 = 0x0007, .ghz2 = 0x0007, NOUPLOAD, },
+  [B2055_C2_TX_RF_SPAD]		= { .ghz5 = 0x0007, .ghz2 = 0x0007, NOUPLOAD, },
+  [B2055_C2_TX_RF_CNTPGA1]	= { .ghz5 = 0x0015, .ghz2 = 0x0015, NOUPLOAD, },
+  [B2055_C2_TX_RF_CNTPAD1]	= { .ghz5 = 0x0055, .ghz2 = 0x0055, NOUPLOAD, },
+  [B2055_C2_TX_RF_PGAIDAC]	= { .ghz5 = 0x0097, .ghz2 = 0x0097, UPLOAD, },
+  [B2055_C2_TX_PGAPADTN]	= { .ghz5 = 0x0008, .ghz2 = 0x0008, NOUPLOAD, },
+  [B2055_C2_TX_PADIDAC1]	= { .ghz5 = 0x0014, .ghz2 = 0x0014, UPLOAD, },
+  [B2055_C2_TX_PADIDAC2]	= { .ghz5 = 0x0033, .ghz2 = 0x0033, NOUPLOAD, },
+  [B2055_C2_TX_MXBGTRIM]	= { .ghz5 = 0x0088, .ghz2 = 0x0088, NOUPLOAD, },
+  [B2055_C2_TX_RF_RCAL]		= { .ghz5 = 0x0006, .ghz2 = 0x0006, NOUPLOAD, },
+  [B2055_C2_TX_RF_PADTSSI1]	= { .ghz5 = 0x0003, .ghz2 = 0x0003, UPLOAD, },
+  [B2055_C2_TX_RF_PADTSSI2]	= { .ghz5 = 0x000A, .ghz2 = 0x000A, NOUPLOAD, },
+  [B2055_C2_TX_RF_SPARE]	= { .ghz5 = 0x0003, .ghz2 = 0x0003, UPLOAD, },
+  [B2055_C2_TX_RF_IQCAL1]	= { .ghz5 = 0x002A, .ghz2 = 0x002A, NOUPLOAD, },
+  [B2055_C2_TX_RF_IQCAL2]	= { .ghz5 = 0x00A4, .ghz2 = 0x00A4, NOUPLOAD, },
+  [B2055_C2_TXBB_RCCAL]		= { .ghz5 = 0x0018, .ghz2 = 0x0018, NOUPLOAD, },
+  [B2055_C2_TXBB_LPF1]		= { .ghz5 = 0x0028, .ghz2 = 0x0028, NOUPLOAD, },
+  [B2055_C2_TX_VOSCNCL]		= { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+  [B2055_C2_TX_LPF_MXGMIDAC]	= { .ghz5 = 0x004A, .ghz2 = 0x004A, NOUPLOAD, },
+  [B2055_C2_TX_BB_MXGM]		= { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+  [B2055_PRG_GCHP21]		= { .ghz5 = 0x0071, .ghz2 = 0x0071, NOUPLOAD, },
+  [B2055_PRG_GCHP22]		= { .ghz5 = 0x0072, .ghz2 = 0x0072, NOUPLOAD, },
+  [B2055_PRG_GCHP23]		= { .ghz5 = 0x0073, .ghz2 = 0x0073, NOUPLOAD, },
+  [B2055_PRG_GCHP24]		= { .ghz5 = 0x0074, .ghz2 = 0x0074, NOUPLOAD, },
+  [B2055_PRG_GCHP25]		= { .ghz5 = 0x0075, .ghz2 = 0x0075, NOUPLOAD, },
+  [B2055_PRG_GCHP26]		= { .ghz5 = 0x0076, .ghz2 = 0x0076, NOUPLOAD, },
+  [B2055_PRG_GCHP27]		= { .ghz5 = 0x0077, .ghz2 = 0x0077, NOUPLOAD, },
+  [B2055_PRG_GCHP28]		= { .ghz5 = 0x0078, .ghz2 = 0x0078, NOUPLOAD, },
+  [B2055_PRG_GCHP29]		= { .ghz5 = 0x0079, .ghz2 = 0x0079, NOUPLOAD, },
+  [B2055_PRG_GCHP30]		= { .ghz5 = 0x007A, .ghz2 = 0x007A, NOUPLOAD, },
+  [0xC7]			= { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+  [0xC8]			= { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+  [0xC9]			= { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+  [0xCA]			= { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+  [0xCB]			= { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+  [0xCC]			= { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+  [B2055_C1_LNA_GAINBST]	= { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+  [0xCE]			= { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+  [0xCF]			= { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+  [0xD0]			= { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+  [0xD1]			= { .ghz5 = 0x0018, .ghz2 = 0x0018, NOUPLOAD, },
+  [B2055_C1_B0NB_RSSIVCM]	= { .ghz5 = 0x0088, .ghz2 = 0x0088, NOUPLOAD, },
+  [0xD3]			= { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+  [0xD4]			= { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+  [0xD5]			= { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+  [B2055_C1_GENSPARE2]		= { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+  [0xD7]			= { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+  [0xD8]			= { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+  [B2055_C2_LNA_GAINBST]	= { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+  [0xDA]			= { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+  [0xDB]			= { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+  [0xDC]			= { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+  [0xDD]			= { .ghz5 = 0x0018, .ghz2 = 0x0018, NOUPLOAD, },
+  [B2055_C2_B0NB_RSSIVCM]	= { .ghz5 = 0x0088, .ghz2 = 0x0088, NOUPLOAD, },
+  [0xDF]			= { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+  [0xE0]			= { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+  [0xE1]			= { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+  [B2055_C2_GENSPARE2]		= { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+};
+
+
+void b2055_upload_inittab(struct b43_wldev *dev,
+			  bool ghz5, bool ignore_uploadflag)
+{
+	const struct b2055_inittab_entry *e;
+	unsigned int i;
+	u16 value;
+
+	for (i = 0; i < ARRAY_SIZE(b2055_inittab); i++) {
+		e = &(b2055_inittab[i]);
+		if (!(e->flags & B2055_INITTAB_ENTRY_OK))
+			continue;
+		if ((e->flags & B2055_INITTAB_UPLOAD) || ignore_uploadflag) {
+			if (ghz5)
+				value = e->ghz5;
+			else
+				value = e->ghz2;
+			b43_radio_write16(dev, i, value);
+		}
+	}
+}
+
+
+#define RADIOREGS(r0, r1, r2, r3, r4, r5, r6, r7, r8, r9, r10, r11, \
+		  r12, r13, r14, r15, r16, r17, r18, r19, r20, r21) \
+	.radio_pll_ref		= r0,	\
+	.radio_rf_pllmod0	= r1,	\
+	.radio_rf_pllmod1	= r2,	\
+	.radio_vco_captail	= r3,	\
+	.radio_vco_cal1		= r4,	\
+	.radio_vco_cal2		= r5,	\
+	.radio_pll_lfc1		= r6,	\
+	.radio_pll_lfr1		= r7,	\
+	.radio_pll_lfc2		= r8,	\
+	.radio_lgbuf_cenbuf	= r9,	\
+	.radio_lgen_tune1	= r10,	\
+	.radio_lgen_tune2	= r11,	\
+	.radio_c1_lgbuf_atune	= r12,	\
+	.radio_c1_lgbuf_gtune	= r13,	\
+	.radio_c1_rx_rfr1	= r14,	\
+	.radio_c1_tx_pgapadtn	= r15,	\
+	.radio_c1_tx_mxbgtrim	= r16,	\
+	.radio_c2_lgbuf_atune	= r17,	\
+	.radio_c2_lgbuf_gtune	= r18,	\
+	.radio_c2_rx_rfr1	= r19,	\
+	.radio_c2_tx_pgapadtn	= r20,	\
+	.radio_c2_tx_mxbgtrim	= r21
+
+#define PHYREGS(r0, r1, r2, r3, r4, r5)	\
+	.phy_bw1a	= r0,		\
+	.phy_bw2	= r1,		\
+	.phy_bw3	= r2,		\
+	.phy_bw4	= r3,		\
+	.phy_bw5	= r4,		\
+	.phy_bw6	= r5
+
+static const struct b43_nphy_channeltab_entry b43_nphy_channeltab[] = {
+  {	.channel		= 184,
+	.freq			= 4920, /* MHz */
+	.unk2			= 3280,
+	RADIOREGS(0x71, 0x01, 0xEC, 0x0F, 0xFF, 0x01, 0x04, 0x0A,
+		  0x00, 0x8F, 0xFF, 0xFF, 0xFF, 0x00, 0x0F, 0x0F,
+		  0x8F, 0xFF, 0x00, 0x0F, 0x0F, 0x8F),
+	PHYREGS(0xB407, 0xB007, 0xAC07, 0x1402, 0x1502, 0x1602),
+  },
+  {	.channel		= 186,
+	.freq			= 4930, /* MHz */
+	.unk2			= 3287,
+	RADIOREGS(0x71, 0x01, 0xED, 0x0F, 0xFF, 0x01, 0x04, 0x0A,
+		  0x00, 0x8F, 0xFF, 0xFF, 0xFF, 0x00, 0x0F, 0x0F,
+		  0x8F, 0xFF, 0x00, 0x0F, 0x0F, 0x8F),
+	PHYREGS(0xB807, 0xB407, 0xB007, 0x1302, 0x1402, 0x1502),
+  },
+  {	.channel		= 188,
+	.freq			= 4940, /* MHz */
+	.unk2			= 3293,
+	RADIOREGS(0x71, 0x01, 0xEE, 0x0F, 0xFF, 0x01, 0x04, 0x0A,
+		  0x00, 0x8F, 0xEE, 0xEE, 0xFF, 0x00, 0x0F, 0x0F,
+		  0x8F, 0xFF, 0x00, 0x0F, 0x0F, 0x8F),
+	PHYREGS(0xBC07, 0xB807, 0xB407, 0x1202, 0x1302, 0x1402),
+  },
+  {	.channel		= 190,
+	.freq			= 4950, /* MHz */
+	.unk2			= 3300,
+	RADIOREGS(0x71, 0x01, 0xEF, 0x0F, 0xFF, 0x01, 0x04, 0x0A,
+		  0x00, 0x8F, 0xEE, 0xEE, 0xFF, 0x00, 0x0F, 0x0F,
+		  0x8F, 0xFF, 0x00, 0x0F, 0x0F, 0x8F),
+	PHYREGS(0xC007, 0xBC07, 0xB807, 0x1102, 0x1202, 0x1302),
+  },
+  {	.channel		= 192,
+	.freq			= 4960, /* MHz */
+	.unk2			= 3307,
+	RADIOREGS(0x71, 0x01, 0xF0, 0x0F, 0xFF, 0x01, 0x04, 0x0A,
+		  0x00, 0x8F, 0xEE, 0xEE, 0xFF, 0x00, 0x0F, 0x0F,
+		  0x8F, 0xFF, 0x00, 0x0F, 0x0F, 0x8F),
+	PHYREGS(0xC407, 0xC007, 0xBC07, 0x0F02, 0x1102, 0x1202),
+  },
+  {	.channel		= 194,
+	.freq			= 4970, /* MHz */
+	.unk2			= 3313,
+	RADIOREGS(0x71, 0x01, 0xF1, 0x0F, 0xFF, 0x01, 0x04, 0x0A,
+		  0x00, 0x8F, 0xEE, 0xEE, 0xFF, 0x00, 0x0F, 0x0F,
+		  0x8F, 0xFF, 0x00, 0x0F, 0x0F, 0x8F),
+	PHYREGS(0xC807, 0xC407, 0xC007, 0x0E02, 0x0F02, 0x1102),
+  },
+  {	.channel		= 196,
+	.freq			= 4980, /* MHz */
+	.unk2			= 3320,
+	RADIOREGS(0x71, 0x01, 0xF2, 0x0E, 0xFF, 0x01, 0x04, 0x0A,
+		  0x00, 0x8F, 0xDD, 0xDD, 0xFF, 0x00, 0x0F, 0x0F,
+		  0x8F, 0xFF, 0x00, 0x0F, 0x0F, 0x8F),
+	PHYREGS(0xCC07, 0xC807, 0xC407, 0x0D02, 0x0E02, 0x0F02),
+  },
+  {	.channel		= 198,
+	.freq			= 4990, /* MHz */
+	.unk2			= 3327,
+	RADIOREGS(0x71, 0x01, 0xF3, 0x0E, 0xFF, 0x01, 0x04, 0x0A,
+		  0x00, 0x8F, 0xDD, 0xDD, 0xFF, 0x00, 0x0F, 0x0F,
+		  0x8F, 0xFF, 0x00, 0x0F, 0x0F, 0x8F),
+	PHYREGS(0xD007, 0xCC07, 0xC807, 0x0C02, 0x0D02, 0x0E02),
+  },
+  {	.channel		= 200,
+	.freq			= 5000, /* MHz */
+	.unk2			= 3333,
+	RADIOREGS(0x71, 0x01, 0xF4, 0x0E, 0xFF, 0x01, 0x04, 0x0A,
+		  0x00, 0x8F, 0xDD, 0xDD, 0xFF, 0x00, 0x0F, 0x0F,
+		  0x8F, 0xFF, 0x00, 0x0F, 0x0F, 0x8F),
+	PHYREGS(0xD407, 0xD007, 0xCC07, 0x0B02, 0x0C02, 0x0D02),
+  },
+  {	.channel		= 202,
+	.freq			= 5010, /* MHz */
+	.unk2			= 3340,
+	RADIOREGS(0x71, 0x01, 0xF5, 0x0E, 0xFF, 0x01, 0x04, 0x0A,
+		  0x00, 0x8F, 0xDD, 0xDD, 0xFF, 0x00, 0x0F, 0x0F,
+		  0x8F, 0xFF, 0x00, 0x0F, 0x0F, 0x8F),
+	PHYREGS(0xD807, 0xD407, 0xD007, 0x0A02, 0x0B02, 0x0C02),
+  },
+  {	.channel		= 204,
+	.freq			= 5020, /* MHz */
+	.unk2			= 3347,
+	RADIOREGS(0x71, 0x01, 0xF6, 0x0E, 0xF7, 0x01, 0x04, 0x0A,
+		  0x00, 0x8F, 0xCC, 0xCC, 0xFF, 0x00, 0x0F, 0x0F,
+		  0x8F, 0xFF, 0x00, 0x0F, 0x0F, 0x8F),
+	PHYREGS(0xDC07, 0xD807, 0xD407, 0x0902, 0x0A02, 0x0B02),
+  },
+  {	.channel		= 206,
+	.freq			= 5030, /* MHz */
+	.unk2			= 3353,
+	RADIOREGS(0x71, 0x01, 0xF7, 0x0E, 0xF7, 0x01, 0x04, 0x0A,
+		  0x00, 0x8F, 0xCC, 0xCC, 0xFF, 0x00, 0x0F, 0x0F,
+		  0x8F, 0xFF, 0x00, 0x0F, 0x0F, 0x8F),
+	PHYREGS(0xE007, 0xDC07, 0xD807, 0x0802, 0x0902, 0x0A02),
+  },
+  {	.channel		= 208,
+	.freq			= 5040, /* MHz */
+	.unk2			= 3360,
+	RADIOREGS(0x71, 0x01, 0xF8, 0x0D, 0xEF, 0x01, 0x04, 0x0A,
+		  0x00, 0x8F, 0xCC, 0xCC, 0xFF, 0x00, 0x0F, 0x0F,
+		  0x8F, 0xFF, 0x00, 0x0F, 0x0F, 0x8F),
+	PHYREGS(0xE407, 0xE007, 0xDC07, 0x0702, 0x0802, 0x0902),
+  },
+  {	.channel		= 210,
+	.freq			= 5050, /* MHz */
+	.unk2			= 3367,
+	RADIOREGS(0x71, 0x01, 0xF9, 0x0D, 0xEF, 0x01, 0x04, 0x0A,
+		  0x00, 0x8F, 0xCC, 0xCC, 0xFF, 0x00, 0x0F, 0x0F,
+		  0x8F, 0xFF, 0x00, 0x0F, 0x0F, 0x8F),
+	PHYREGS(0xE807, 0xE407, 0xE007, 0x0602, 0x0702, 0x0802),
+  },
+  {	.channel		= 212,
+	.freq			= 5060, /* MHz */
+	.unk2			= 3373,
+	RADIOREGS(0x71, 0x01, 0xFA, 0x0D, 0xE6, 0x01, 0x04, 0x0A,
+		  0x00, 0x8F, 0xBB, 0xBB, 0xFF, 0x00, 0x0E, 0x0F,
+		  0x8E, 0xFF, 0x00, 0x0E, 0x0F, 0x8E),
+	PHYREGS(0xEC07, 0xE807, 0xE407, 0x0502, 0x0602, 0x0702),
+  },
+  {	.channel		= 214,
+	.freq			= 5070, /* MHz */
+	.unk2			= 3380,
+	RADIOREGS(0x71, 0x01, 0xFB, 0x0D, 0xE6, 0x01, 0x04, 0x0A,
+		  0x00, 0x8F, 0xBB, 0xBB, 0xFF, 0x00, 0x0E, 0x0F,
+		  0x8E, 0xFF, 0x00, 0x0E, 0x0F, 0x8E),
+	PHYREGS(0xF007, 0xEC07, 0xE807, 0x0402, 0x0502, 0x0602),
+  },
+  {	.channel		= 216,
+	.freq			= 5080, /* MHz */
+	.unk2			= 3387,
+	RADIOREGS(0x71, 0x01, 0xFC, 0x0D, 0xDE, 0x01, 0x04, 0x0A,
+		  0x00, 0x8E, 0xBB, 0xBB, 0xEE, 0x00, 0x0E, 0x0F,
+		  0x8D, 0xEE, 0x00, 0x0E, 0x0F, 0x8D),
+	PHYREGS(0xF407, 0xF007, 0xEC07, 0x0302, 0x0402, 0x0502),
+  },
+  {	.channel		= 218,
+	.freq			= 5090, /* MHz */
+	.unk2			= 3393,
+	RADIOREGS(0x71, 0x01, 0xFD, 0x0D, 0xDE, 0x01, 0x04, 0x0A,
+		  0x00, 0x8E, 0xBB, 0xBB, 0xEE, 0x00, 0x0E, 0x0F,
+		  0x8D, 0xEE, 0x00, 0x0E, 0x0F, 0x8D),
+	PHYREGS(0xF807, 0xF407, 0xF007, 0x0202, 0x0302, 0x0402),
+  },
+  {	.channel		= 220,
+	.freq			= 5100, /* MHz */
+	.unk2			= 3400,
+	RADIOREGS(0x71, 0x01, 0xFE, 0x0C, 0xD6, 0x01, 0x04, 0x0A,
+		  0x00, 0x8E, 0xAA, 0xAA, 0xEE, 0x00, 0x0D, 0x0F,
+		  0x8D, 0xEE, 0x00, 0x0D, 0x0F, 0x8D),
+	PHYREGS(0xFC07, 0xF807, 0xF407, 0x0102, 0x0202, 0x0302),
+  },
+  {	.channel		= 222,
+	.freq			= 5110, /* MHz */
+	.unk2			= 3407,
+	RADIOREGS(0x71, 0x01, 0xFF, 0x0C, 0xD6, 0x01, 0x04, 0x0A,
+		  0x00, 0x8E, 0xAA, 0xAA, 0xEE, 0x00, 0x0D, 0x0F,
+		  0x8D, 0xEE, 0x00, 0x0D, 0x0F, 0x8D),
+	PHYREGS(0x0008, 0xFC07, 0xF807, 0x0002, 0x0102, 0x0202),
+  },
+  {	.channel		= 224,
+	.freq			= 5120, /* MHz */
+	.unk2			= 3413,
+	RADIOREGS(0x71, 0x02, 0x00, 0x0C, 0xCE, 0x01, 0x04, 0x0A,
+		  0x00, 0x8D, 0xAA, 0xAA, 0xDD, 0x00, 0x0D, 0x0F,
+		  0x8C, 0xDD, 0x00, 0x0D, 0x0F, 0x8C),
+	PHYREGS(0x0408, 0x0008, 0xFC07, 0xFF01, 0x0002, 0x0102),
+  },
+  {	.channel		= 226,
+	.freq			= 5130, /* MHz */
+	.unk2			= 3420,
+	RADIOREGS(0x71, 0x02, 0x01, 0x0C, 0xCE, 0x01, 0x04, 0x0A,
+		  0x00, 0x8D, 0xAA, 0xAA, 0xDD, 0x00, 0x0D, 0x0F,
+		  0x8C, 0xDD, 0x00, 0x0D, 0x0F, 0x8C),
+	PHYREGS(0x0808, 0x0408, 0x0008, 0xFE01, 0xFF01, 0x0002),
+  },
+  {	.channel		= 228,
+	.freq			= 5140, /* MHz */
+	.unk2			= 3427,
+	RADIOREGS(0x71, 0x02, 0x02, 0x0C, 0xC6, 0x01, 0x04, 0x0A,
+		  0x00, 0x8D, 0x99, 0x99, 0xDD, 0x00, 0x0C, 0x0E,
+		  0x8B, 0xDD, 0x00, 0x0C, 0x0E, 0x8B),
+	PHYREGS(0x0C08, 0x0808, 0x0408, 0xFD01, 0xFE01, 0xFF01),
+  },
+  {	.channel		= 32,
+	.freq			= 5160, /* MHz */
+	.unk2			= 3440,
+	RADIOREGS(0x71, 0x02, 0x04, 0x0B, 0xBE, 0x01, 0x04, 0x0A,
+		  0x00, 0x8C, 0x99, 0x99, 0xCC, 0x00, 0x0B, 0x0D,
+		  0x8A, 0xCC, 0x00, 0x0B, 0x0D, 0x8A),
+	PHYREGS(0x1408, 0x1008, 0x0C08, 0xFB01, 0xFC01, 0xFD01),
+  },
+  {	.channel		= 34,
+	.freq			= 5170, /* MHz */
+	.unk2			= 3447,
+	RADIOREGS(0x71, 0x02, 0x05, 0x0B, 0xBE, 0x01, 0x04, 0x0A,
+		  0x00, 0x8C, 0x99, 0x99, 0xCC, 0x00, 0x0B, 0x0D,
+		  0x8A, 0xCC, 0x00, 0x0B, 0x0D, 0x8A),
+	PHYREGS(0x1808, 0x1408, 0x1008, 0xFA01, 0xFB01, 0xFC01),
+  },
+  {	.channel		= 36,
+	.freq			= 5180, /* MHz */
+	.unk2			= 3453,
+	RADIOREGS(0x71, 0x02, 0x06, 0x0B, 0xB6, 0x01, 0x04, 0x0A,
+		  0x00, 0x8C, 0x88, 0x88, 0xCC, 0x00, 0x0B, 0x0C,
+		  0x89, 0xCC, 0x00, 0x0B, 0x0C, 0x89),
+	PHYREGS(0x1C08, 0x1808, 0x1408, 0xF901, 0xFA01, 0xFB01),
+  },
+  {	.channel		= 38,
+	.freq			= 5190, /* MHz */
+	.unk2			= 3460,
+	RADIOREGS(0x71, 0x02, 0x07, 0x0B, 0xB6, 0x01, 0x04, 0x0A,
+		  0x00, 0x8C, 0x88, 0x88, 0xCC, 0x00, 0x0B, 0x0C,
+		  0x89, 0xCC, 0x00, 0x0B, 0x0C, 0x89),
+	PHYREGS(0x2008, 0x1C08, 0x1808, 0xF801, 0xF901, 0xFA01),
+  },
+  {	.channel		= 40,
+	.freq			= 5200, /* MHz */
+	.unk2			= 3467,
+	RADIOREGS(0x71, 0x02, 0x08, 0x0B, 0xAF, 0x01, 0x04, 0x0A,
+		  0x00, 0x8B, 0x88, 0x88, 0xBB, 0x00, 0x0A, 0x0B,
+		  0x89, 0xBB, 0x00, 0x0A, 0x0B, 0x89),
+	PHYREGS(0x2408, 0x2008, 0x1C08, 0xF701, 0xF801, 0xF901),
+  },
+  {	.channel		= 42,
+	.freq			= 5210, /* MHz */
+	.unk2			= 3473,
+	RADIOREGS(0x71, 0x02, 0x09, 0x0B, 0xAF, 0x01, 0x04, 0x0A,
+		  0x00, 0x8B, 0x88, 0x88, 0xBB, 0x00, 0x0A, 0x0B,
+		  0x89, 0xBB, 0x00, 0x0A, 0x0B, 0x89),
+	PHYREGS(0x2808, 0x2408, 0x2008, 0xF601, 0xF701, 0xF801),
+  },
+  {	.channel		= 44,
+	.freq			= 5220, /* MHz */
+	.unk2			= 3480,
+	RADIOREGS(0x71, 0x02, 0x0A, 0x0A, 0xA7, 0x01, 0x04, 0x0A,
+		  0x00, 0x8B, 0x77, 0x77, 0xBB, 0x00, 0x09, 0x0A,
+		  0x88, 0xBB, 0x00, 0x09, 0x0A, 0x88),
+	PHYREGS(0x2C08, 0x2808, 0x2408, 0xF501, 0xF601, 0xF701),
+  },
+  {	.channel		= 46,
+	.freq			= 5230, /* MHz */
+	.unk2			= 3487,
+	RADIOREGS(0x71, 0x02, 0x0B, 0x0A, 0xA7, 0x01, 0x04, 0x0A,
+		  0x00, 0x8B, 0x77, 0x77, 0xBB, 0x00, 0x09, 0x0A,
+		  0x88, 0xBB, 0x00, 0x09, 0x0A, 0x88),
+	PHYREGS(0x3008, 0x2C08, 0x2808, 0xF401, 0xF501, 0xF601),
+  },
+  {	.channel		= 48,
+	.freq			= 5240, /* MHz */
+	.unk2			= 3493,
+	RADIOREGS(0x71, 0x02, 0x0C, 0x0A, 0xA0, 0x01, 0x04, 0x0A,
+		  0x00, 0x8A, 0x77, 0x77, 0xAA, 0x00, 0x09, 0x0A,
+		  0x87, 0xAA, 0x00, 0x09, 0x0A, 0x87),
+	PHYREGS(0x3408, 0x3008, 0x2C08, 0xF301, 0xF401, 0xF501),
+  },
+  {	.channel		= 50,
+	.freq			= 5250, /* MHz */
+	.unk2			= 3500,
+	RADIOREGS(0x71, 0x02, 0x0D, 0x0A, 0xA0, 0x01, 0x04, 0x0A,
+		  0x00, 0x8A, 0x77, 0x77, 0xAA, 0x00, 0x09, 0x0A,
+		  0x87, 0xAA, 0x00, 0x09, 0x0A, 0x87),
+	PHYREGS(0x3808, 0x3408, 0x3008, 0xF201, 0xF301, 0xF401),
+  },
+  {	.channel		= 52,
+	.freq			= 5260, /* MHz */
+	.unk2			= 3507,
+	RADIOREGS(0x71, 0x02, 0x0E, 0x0A, 0x98, 0x01, 0x04, 0x0A,
+		  0x00, 0x8A, 0x66, 0x66, 0xAA, 0x00, 0x08, 0x09,
+		  0x87, 0xAA, 0x00, 0x08, 0x09, 0x87),
+	PHYREGS(0x3C08, 0x3808, 0x3408, 0xF101, 0xF201, 0xF301),
+  },
+  {	.channel		= 54,
+	.freq			= 5270, /* MHz */
+	.unk2			= 3513,
+	RADIOREGS(0x71, 0x02, 0x0F, 0x0A, 0x98, 0x01, 0x04, 0x0A,
+		  0x00, 0x8A, 0x66, 0x66, 0xAA, 0x00, 0x08, 0x09,
+		  0x87, 0xAA, 0x00, 0x08, 0x09, 0x87),
+	PHYREGS(0x4008, 0x3C08, 0x3808, 0xF001, 0xF101, 0xF201),
+  },
+  {	.channel		= 56,
+	.freq			= 5280, /* MHz */
+	.unk2			= 3520,
+	RADIOREGS(0x71, 0x02, 0x10, 0x09, 0x91, 0x01, 0x04, 0x0A,
+		  0x00, 0x89, 0x66, 0x66, 0x99, 0x00, 0x08, 0x08,
+		  0x86, 0x99, 0x00, 0x08, 0x08, 0x86),
+	PHYREGS(0x4408, 0x4008, 0x3C08, 0xF001, 0xF001, 0xF101),
+  },
+  {	.channel		= 58,
+	.freq			= 5290, /* MHz */
+	.unk2			= 3527,
+	RADIOREGS(0x71, 0x02, 0x11, 0x09, 0x91, 0x01, 0x04, 0x0A,
+		  0x00, 0x89, 0x66, 0x66, 0x99, 0x00, 0x08, 0x08,
+		  0x86, 0x99, 0x00, 0x08, 0x08, 0x86),
+	PHYREGS(0x4808, 0x4408, 0x4008, 0xEF01, 0xF001, 0xF001),
+  },
+  {	.channel		= 60,
+	.freq			= 5300, /* MHz */
+	.unk2			= 3533,
+	RADIOREGS(0x71, 0x02, 0x12, 0x09, 0x8A, 0x01, 0x04, 0x0A,
+		  0x00, 0x89, 0x55, 0x55, 0x99, 0x00, 0x08, 0x07,
+		  0x85, 0x99, 0x00, 0x08, 0x07, 0x85),
+	PHYREGS(0x4C08, 0x4808, 0x4408, 0xEE01, 0xEF01, 0xF001),
+  },
+  {	.channel		= 62,
+	.freq			= 5310, /* MHz */
+	.unk2			= 3540,
+	RADIOREGS(0x71, 0x02, 0x13, 0x09, 0x8A, 0x01, 0x04, 0x0A,
+		  0x00, 0x89, 0x55, 0x55, 0x99, 0x00, 0x08, 0x07,
+		  0x85, 0x99, 0x00, 0x08, 0x07, 0x85),
+	PHYREGS(0x5008, 0x4C08, 0x4808, 0xED01, 0xEE01, 0xEF01),
+  },
+  {	.channel		= 64,
+	.freq			= 5320, /* MHz */
+	.unk2			= 3547,
+	RADIOREGS(0x71, 0x02, 0x14, 0x09, 0x83, 0x01, 0x04, 0x0A,
+		  0x00, 0x88, 0x55, 0x55, 0x88, 0x00, 0x07, 0x07,
+		  0x84, 0x88, 0x00, 0x07, 0x07, 0x84),
+	PHYREGS(0x5408, 0x5008, 0x4C08, 0xEC01, 0xED01, 0xEE01),
+  },
+  {	.channel		= 66,
+	.freq			= 5330, /* MHz */
+	.unk2			= 3553,
+	RADIOREGS(0x71, 0x02, 0x15, 0x09, 0x83, 0x01, 0x04, 0x0A,
+		  0x00, 0x88, 0x55, 0x55, 0x88, 0x00, 0x07, 0x07,
+		  0x84, 0x88, 0x00, 0x07, 0x07, 0x84),
+	PHYREGS(0x5808, 0x5408, 0x5008, 0xEB01, 0xEC01, 0xED01),
+  },
+  {	.channel		= 68,
+	.freq			= 5340, /* MHz */
+	.unk2			= 3560,
+	RADIOREGS(0x71, 0x02, 0x16, 0x08, 0x7C, 0x01, 0x04, 0x0A,
+		  0x00, 0x88, 0x44, 0x44, 0x88, 0x00, 0x07, 0x06,
+		  0x84, 0x88, 0x00, 0x07, 0x06, 0x84),
+	PHYREGS(0x5C08, 0x5808, 0x5408, 0xEA01, 0xEB01, 0xEC01),
+  },
+  {	.channel		= 70,
+	.freq			= 5350, /* MHz */
+	.unk2			= 3567,
+	RADIOREGS(0x71, 0x02, 0x17, 0x08, 0x7C, 0x01, 0x04, 0x0A,
+		  0x00, 0x88, 0x44, 0x44, 0x88, 0x00, 0x07, 0x06,
+		  0x84, 0x88, 0x00, 0x07, 0x06, 0x84),
+	PHYREGS(0x6008, 0x5C08, 0x5808, 0xE901, 0xEA01, 0xEB01),
+  },
+  {	.channel		= 72,
+	.freq			= 5360, /* MHz */
+	.unk2			= 3573,
+	RADIOREGS(0x71, 0x02, 0x18, 0x08, 0x75, 0x01, 0x04, 0x0A,
+		  0x00, 0x87, 0x44, 0x44, 0x77, 0x00, 0x06, 0x05,
+		  0x83, 0x77, 0x00, 0x06, 0x05, 0x83),
+	PHYREGS(0x6408, 0x6008, 0x5C08, 0xE801, 0xE901, 0xEA01),
+  },
+  {	.channel		= 74,
+	.freq			= 5370, /* MHz */
+	.unk2			= 3580,
+	RADIOREGS(0x71, 0x02, 0x19, 0x08, 0x75, 0x01, 0x04, 0x0A,
+		  0x00, 0x87, 0x44, 0x44, 0x77, 0x00, 0x06, 0x05,
+		  0x83, 0x77, 0x00, 0x06, 0x05, 0x83),
+	PHYREGS(0x6808, 0x6408, 0x6008, 0xE701, 0xE801, 0xE901),
+  },
+  {	.channel		= 76,
+	.freq			= 5380, /* MHz */
+	.unk2			= 3587,
+	RADIOREGS(0x71, 0x02, 0x1A, 0x08, 0x6E, 0x01, 0x04, 0x0A,
+		  0x00, 0x87, 0x33, 0x33, 0x77, 0x00, 0x06, 0x04,
+		  0x82, 0x77, 0x00, 0x06, 0x04, 0x82),
+	PHYREGS(0x6C08, 0x6808, 0x6408, 0xE601, 0xE701, 0xE801),
+  },
+  {	.channel		= 78,
+	.freq			= 5390, /* MHz */
+	.unk2			= 3593,
+	RADIOREGS(0x71, 0x02, 0x1B, 0x08, 0x6E, 0x01, 0x04, 0x0A,
+		  0x00, 0x87, 0x33, 0x33, 0x77, 0x00, 0x06, 0x04,
+		  0x82, 0x77, 0x00, 0x06, 0x04, 0x82),
+	PHYREGS(0x7008, 0x6C08, 0x6808, 0xE501, 0xE601, 0xE701),
+  },
+  {	.channel		= 80,
+	.freq			= 5400, /* MHz */
+	.unk2			= 3600,
+	RADIOREGS(0x71, 0x02, 0x1C, 0x07, 0x67, 0x01, 0x04, 0x0A,
+		  0x00, 0x86, 0x33, 0x33, 0x66, 0x00, 0x05, 0x04,
+		  0x81, 0x66, 0x00, 0x05, 0x04, 0x81),
+	PHYREGS(0x7408, 0x7008, 0x6C08, 0xE501, 0xE501, 0xE601),
+  },
+  {	.channel		= 82,
+	.freq			= 5410, /* MHz */
+	.unk2			= 3607,
+	RADIOREGS(0x71, 0x02, 0x1D, 0x07, 0x67, 0x01, 0x04, 0x0A,
+		  0x00, 0x86, 0x33, 0x33, 0x66, 0x00, 0x05, 0x04,
+		  0x81, 0x66, 0x00, 0x05, 0x04, 0x81),
+	PHYREGS(0x7808, 0x7408, 0x7008, 0xE401, 0xE501, 0xE501),
+  },
+  {	.channel		= 84,
+	.freq			= 5420, /* MHz */
+	.unk2			= 3613,
+	RADIOREGS(0x71, 0x02, 0x1E, 0x07, 0x61, 0x01, 0x04, 0x0A,
+		  0x00, 0x86, 0x22, 0x22, 0x66, 0x00, 0x05, 0x03,
+		  0x80, 0x66, 0x00, 0x05, 0x03, 0x80),
+	PHYREGS(0x7C08, 0x7808, 0x7408, 0xE301, 0xE401, 0xE501),
+  },
+  {	.channel		= 86,
+	.freq			= 5430, /* MHz */
+	.unk2			= 3620,
+	RADIOREGS(0x71, 0x02, 0x1F, 0x07, 0x61, 0x01, 0x04, 0x0A,
+		  0x00, 0x86, 0x22, 0x22, 0x66, 0x00, 0x05, 0x03,
+		  0x80, 0x66, 0x00, 0x05, 0x03, 0x80),
+	PHYREGS(0x8008, 0x7C08, 0x7808, 0xE201, 0xE301, 0xE401),
+  },
+  {	.channel		= 88,
+	.freq			= 5440, /* MHz */
+	.unk2			= 3627,
+	RADIOREGS(0x71, 0x02, 0x20, 0x07, 0x5A, 0x01, 0x04, 0x0A,
+		  0x00, 0x85, 0x22, 0x22, 0x55, 0x00, 0x04, 0x02,
+		  0x80, 0x55, 0x00, 0x04, 0x02, 0x80),
+	PHYREGS(0x8408, 0x8008, 0x7C08, 0xE101, 0xE201, 0xE301),
+  },
+  {	.channel		= 90,
+	.freq			= 5450, /* MHz */
+	.unk2			= 3633,
+	RADIOREGS(0x71, 0x02, 0x21, 0x07, 0x5A, 0x01, 0x04, 0x0A,
+		  0x00, 0x85, 0x22, 0x22, 0x55, 0x00, 0x04, 0x02,
+		  0x80, 0x55, 0x00, 0x04, 0x02, 0x80),
+	PHYREGS(0x8808, 0x8408, 0x8008, 0xE001, 0xE101, 0xE201),
+  },
+  {	.channel		= 92,
+	.freq			= 5460, /* MHz */
+	.unk2			= 3640,
+	RADIOREGS(0x71, 0x02, 0x22, 0x06, 0x53, 0x01, 0x04, 0x0A,
+		  0x00, 0x85, 0x11, 0x11, 0x55, 0x00, 0x04, 0x01,
+		  0x80, 0x55, 0x00, 0x04, 0x01, 0x80),
+	PHYREGS(0x8C08, 0x8808, 0x8408, 0xDF01, 0xE001, 0xE101),
+  },
+  {	.channel		= 94,
+	.freq			= 5470, /* MHz */
+	.unk2			= 3647,
+	RADIOREGS(0x71, 0x02, 0x23, 0x06, 0x53, 0x01, 0x04, 0x0A,
+		  0x00, 0x85, 0x11, 0x11, 0x55, 0x00, 0x04, 0x01,
+		  0x80, 0x55, 0x00, 0x04, 0x01, 0x80),
+	PHYREGS(0x9008, 0x8C08, 0x8808, 0xDE01, 0xDF01, 0xE001),
+  },
+  {	.channel		= 96,
+	.freq			= 5480, /* MHz */
+	.unk2			= 3653,
+	RADIOREGS(0x71, 0x02, 0x24, 0x06, 0x4D, 0x01, 0x04, 0x0A,
+		  0x00, 0x84, 0x11, 0x11, 0x44, 0x00, 0x03, 0x00,
+		  0x80, 0x44, 0x00, 0x03, 0x00, 0x80),
+	PHYREGS(0x9408, 0x9008, 0x8C08, 0xDD01, 0xDE01, 0xDF01),
+  },
+  {	.channel		= 98,
+	.freq			= 5490, /* MHz */
+	.unk2			= 3660,
+	RADIOREGS(0x71, 0x02, 0x25, 0x06, 0x4D, 0x01, 0x04, 0x0A,
+		  0x00, 0x84, 0x11, 0x11, 0x44, 0x00, 0x03, 0x00,
+		  0x80, 0x44, 0x00, 0x03, 0x00, 0x80),
+	PHYREGS(0x9808, 0x9408, 0x9008, 0xDD01, 0xDD01, 0xDE01),
+  },
+  {	.channel		= 100,
+	.freq			= 5500, /* MHz */
+	.unk2			= 3667,
+	RADIOREGS(0x71, 0x02, 0x26, 0x06, 0x47, 0x01, 0x04, 0x0A,
+		  0x00, 0x84, 0x00, 0x00, 0x44, 0x00, 0x03, 0x00,
+		  0x80, 0x44, 0x00, 0x03, 0x00, 0x80),
+	PHYREGS(0x9C08, 0x9808, 0x9408, 0xDC01, 0xDD01, 0xDD01),
+  },
+  {	.channel		= 102,
+	.freq			= 5510, /* MHz */
+	.unk2			= 3673,
+	RADIOREGS(0x71, 0x02, 0x27, 0x06, 0x47, 0x01, 0x04, 0x0A,
+		  0x00, 0x84, 0x00, 0x00, 0x44, 0x00, 0x03, 0x00,
+		  0x80, 0x44, 0x00, 0x03, 0x00, 0x80),
+	PHYREGS(0xA008, 0x9C08, 0x9808, 0xDB01, 0xDC01, 0xDD01),
+  },
+  {	.channel		= 104,
+	.freq			= 5520, /* MHz */
+	.unk2			= 3680,
+	RADIOREGS(0x71, 0x02, 0x28, 0x05, 0x40, 0x01, 0x04, 0x0A,
+		  0x00, 0x83, 0x00, 0x00, 0x33, 0x00, 0x02, 0x00,
+		  0x80, 0x33, 0x00, 0x02, 0x00, 0x80),
+	PHYREGS(0xA408, 0xA008, 0x9C08, 0xDA01, 0xDB01, 0xDC01),
+  },
+  {	.channel		= 106,
+	.freq			= 5530, /* MHz */
+	.unk2			= 3687,
+	RADIOREGS(0x71, 0x02, 0x29, 0x05, 0x40, 0x01, 0x04, 0x0A,
+		  0x00, 0x83, 0x00, 0x00, 0x33, 0x00, 0x02, 0x00,
+		  0x80, 0x33, 0x00, 0x02, 0x00, 0x80),
+	PHYREGS(0xA808, 0xA408, 0xA008, 0xD901, 0xDA01, 0xDB01),
+  },
+  {	.channel		= 108,
+	.freq			= 5540, /* MHz */
+	.unk2			= 3693,
+	RADIOREGS(0x71, 0x02, 0x2A, 0x05, 0x3A, 0x01, 0x04, 0x0A,
+		  0x00, 0x83, 0x00, 0x00, 0x33, 0x00, 0x02, 0x00,
+		  0x80, 0x33, 0x00, 0x02, 0x00, 0x80),
+	PHYREGS(0xAC08, 0xA808, 0xA408, 0xD801, 0xD901, 0xDA01),
+  },
+  {	.channel		= 110,
+	.freq			= 5550, /* MHz */
+	.unk2			= 3700,
+	RADIOREGS(0x71, 0x02, 0x2B, 0x05, 0x3A, 0x01, 0x04, 0x0A,
+		  0x00, 0x83, 0x00, 0x00, 0x33, 0x00, 0x02, 0x00,
+		  0x80, 0x33, 0x00, 0x02, 0x00, 0x80),
+	PHYREGS(0xB008, 0xAC08, 0xA808, 0xD701, 0xD801, 0xD901),
+  },
+  {	.channel		= 112,
+	.freq			= 5560, /* MHz */
+	.unk2			= 3707,
+	RADIOREGS(0x71, 0x02, 0x2C, 0x05, 0x34, 0x01, 0x04, 0x0A,
+		  0x00, 0x82, 0x00, 0x00, 0x22, 0x00, 0x01, 0x00,
+		  0x80, 0x22, 0x00, 0x01, 0x00, 0x80),
+	PHYREGS(0xB408, 0xB008, 0xAC08, 0xD701, 0xD701, 0xD801),
+  },
+  {	.channel		= 114,
+	.freq			= 5570, /* MHz */
+	.unk2			= 3713,
+	RADIOREGS(0x71, 0x02, 0x2D, 0x05, 0x34, 0x01, 0x04, 0x0A,
+		  0x00, 0x82, 0x00, 0x00, 0x22, 0x00, 0x01, 0x00,
+		  0x80, 0x22, 0x00, 0x01, 0x00, 0x80),
+	PHYREGS(0xB808, 0xB408, 0xB008, 0xD601, 0xD701, 0xD701),
+  },
+  {	.channel		= 116,
+	.freq			= 5580, /* MHz */
+	.unk2			= 3720,
+	RADIOREGS(0x71, 0x02, 0x2E, 0x04, 0x2E, 0x01, 0x04, 0x0A,
+		  0x00, 0x82, 0x00, 0x00, 0x22, 0x00, 0x01, 0x00,
+		  0x80, 0x22, 0x00, 0x01, 0x00, 0x80),
+	PHYREGS(0xBC08, 0xB808, 0xB408, 0xD501, 0xD601, 0xD701),
+  },
+  {	.channel		= 118,
+	.freq			= 5590, /* MHz */
+	.unk2			= 3727,
+	RADIOREGS(0x71, 0x02, 0x2F, 0x04, 0x2E, 0x01, 0x04, 0x0A,
+		  0x00, 0x82, 0x00, 0x00, 0x22, 0x00, 0x01, 0x00,
+		  0x80, 0x22, 0x00, 0x01, 0x00, 0x80),
+	PHYREGS(0xC008, 0xBC08, 0xB808, 0xD401, 0xD501, 0xD601),
+  },
+  {	.channel		= 120,
+	.freq			= 5600, /* MHz */
+	.unk2			= 3733,
+	RADIOREGS(0x71, 0x02, 0x30, 0x04, 0x28, 0x01, 0x04, 0x0A,
+		  0x00, 0x81, 0x00, 0x00, 0x11, 0x00, 0x01, 0x00,
+		  0x80, 0x11, 0x00, 0x01, 0x00, 0x80),
+	PHYREGS(0xC408, 0xC008, 0xBC08, 0xD301, 0xD401, 0xD501),
+  },
+  {	.channel		= 122,
+	.freq			= 5610, /* MHz */
+	.unk2			= 3740,
+	RADIOREGS(0x71, 0x02, 0x31, 0x04, 0x28, 0x01, 0x04, 0x0A,
+		  0x00, 0x81, 0x00, 0x00, 0x11, 0x00, 0x01, 0x00,
+		  0x80, 0x11, 0x00, 0x01, 0x00, 0x80),
+	PHYREGS(0xC808, 0xC408, 0xC008, 0xD201, 0xD301, 0xD401),
+  },
+  {	.channel		= 124,
+	.freq			= 5620, /* MHz */
+	.unk2			= 3747,
+	RADIOREGS(0x71, 0x02, 0x32, 0x04, 0x21, 0x01, 0x04, 0x0A,
+		  0x00, 0x81, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00,
+		  0x80, 0x11, 0x00, 0x00, 0x00, 0x80),
+	PHYREGS(0xCC08, 0xC808, 0xC408, 0xD201, 0xD201, 0xD301),
+  },
+  {	.channel		= 126,
+	.freq			= 5630, /* MHz */
+	.unk2			= 3753,
+	RADIOREGS(0x71, 0x02, 0x33, 0x04, 0x21, 0x01, 0x04, 0x0A,
+		  0x00, 0x81, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00,
+		  0x80, 0x11, 0x00, 0x00, 0x00, 0x80),
+	PHYREGS(0xD008, 0xCC08, 0xC808, 0xD101, 0xD201, 0xD201),
+  },
+  {	.channel		= 128,
+	.freq			= 5640, /* MHz */
+	.unk2			= 3760,
+	RADIOREGS(0x71, 0x02, 0x34, 0x03, 0x1C, 0x01, 0x04, 0x0A,
+		  0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		  0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
+	PHYREGS(0xD408, 0xD008, 0xCC08, 0xD001, 0xD101, 0xD201),
+  },
+  {	.channel		= 130,
+	.freq			= 5650, /* MHz */
+	.unk2			= 3767,
+	RADIOREGS(0x71, 0x02, 0x35, 0x03, 0x1C, 0x01, 0x04, 0x0A,
+		  0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		  0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
+	PHYREGS(0xD808, 0xD408, 0xD008, 0xCF01, 0xD001, 0xD101),
+  },
+  {	.channel		= 132,
+	.freq			= 5660, /* MHz */
+	.unk2			= 3773,
+	RADIOREGS(0x71, 0x02, 0x36, 0x03, 0x16, 0x01, 0x04, 0x0A,
+		  0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		  0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
+	PHYREGS(0xDC08, 0xD808, 0xD408, 0xCE01, 0xCF01, 0xD001),
+  },
+  {	.channel		= 134,
+	.freq			= 5670, /* MHz */
+	.unk2			= 3780,
+	RADIOREGS(0x71, 0x02, 0x37, 0x03, 0x16, 0x01, 0x04, 0x0A,
+		  0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		  0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
+	PHYREGS(0xE008, 0xDC08, 0xD808, 0xCE01, 0xCE01, 0xCF01),
+  },
+  {	.channel		= 136,
+	.freq			= 5680, /* MHz */
+	.unk2			= 3787,
+	RADIOREGS(0x71, 0x02, 0x38, 0x03, 0x10, 0x01, 0x04, 0x0A,
+		  0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		  0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
+	PHYREGS(0xE408, 0xE008, 0xDC08, 0xCD01, 0xCE01, 0xCE01),
+  },
+  {	.channel		= 138,
+	.freq			= 5690, /* MHz */
+	.unk2			= 3793,
+	RADIOREGS(0x71, 0x02, 0x39, 0x03, 0x10, 0x01, 0x04, 0x0A,
+		  0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		  0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
+	PHYREGS(0xE808, 0xE408, 0xE008, 0xCC01, 0xCD01, 0xCE01),
+  },
+  {	.channel		= 140,
+	.freq			= 5700, /* MHz */
+	.unk2			= 3800,
+	RADIOREGS(0x71, 0x02, 0x3A, 0x02, 0x0A, 0x01, 0x04, 0x0A,
+		  0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		  0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
+	PHYREGS(0xEC08, 0xE808, 0xE408, 0xCB01, 0xCC01, 0xCD01),
+  },
+  {	.channel		= 142,
+	.freq			= 5710, /* MHz */
+	.unk2			= 3807,
+	RADIOREGS(0x71, 0x02, 0x3B, 0x02, 0x0A, 0x01, 0x04, 0x0A,
+		  0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		  0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
+	PHYREGS(0xF008, 0xEC08, 0xE808, 0xCA01, 0xCB01, 0xCC01),
+  },
+  {	.channel		= 144,
+	.freq			= 5720, /* MHz */
+	.unk2			= 3813,
+	RADIOREGS(0x71, 0x02, 0x3C, 0x02, 0x0A, 0x01, 0x04, 0x0A,
+		  0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		  0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
+	PHYREGS(0xF408, 0xF008, 0xEC08, 0xC901, 0xCA01, 0xCB01),
+  },
+  {	.channel		= 145,
+	.freq			= 5725, /* MHz */
+	.unk2			= 3817,
+	RADIOREGS(0x72, 0x04, 0x79, 0x02, 0x03, 0x01, 0x03, 0x14,
+		  0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		  0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
+	PHYREGS(0xF608, 0xF208, 0xEE08, 0xC901, 0xCA01, 0xCB01),
+  },
+  {	.channel		= 146,
+	.freq			= 5730, /* MHz */
+	.unk2			= 3820,
+	RADIOREGS(0x71, 0x02, 0x3D, 0x02, 0x0A, 0x01, 0x04, 0x0A,
+		  0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		  0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
+	PHYREGS(0xF808, 0xF408, 0xF008, 0xC901, 0xC901, 0xCA01),
+  },
+  {	.channel		= 147,
+	.freq			= 5735, /* MHz */
+	.unk2			= 3823,
+	RADIOREGS(0x72, 0x04, 0x7B, 0x02, 0x03, 0x01, 0x03, 0x14,
+		  0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		  0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
+	PHYREGS(0xFA08, 0xF608, 0xF208, 0xC801, 0xC901, 0xCA01),
+  },
+  {	.channel		= 148,
+	.freq			= 5740, /* MHz */
+	.unk2			= 3827,
+	RADIOREGS(0x71, 0x02, 0x3E, 0x02, 0x0A, 0x01, 0x04, 0x0A,
+		  0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		  0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
+	PHYREGS(0xFC08, 0xF808, 0xF408, 0xC801, 0xC901, 0xC901),
+  },
+  {	.channel		= 149,
+	.freq			= 5745, /* MHz */
+	.unk2			= 3830,
+	RADIOREGS(0x72, 0x04, 0x7D, 0x02, 0xFE, 0x00, 0x03, 0x14,
+		  0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		  0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
+	PHYREGS(0xFE08, 0xFA08, 0xF608, 0xC801, 0xC801, 0xC901),
+  },
+  {	.channel		= 150,
+	.freq			= 5750, /* MHz */
+	.unk2			= 3833,
+	RADIOREGS(0x71, 0x02, 0x3F, 0x02, 0x0A, 0x01, 0x04, 0x0A,
+		  0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		  0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
+	PHYREGS(0x0009, 0xFC08, 0xF808, 0xC701, 0xC801, 0xC901),
+  },
+  {	.channel		= 151,
+	.freq			= 5755, /* MHz */
+	.unk2			= 3837,
+	RADIOREGS(0x72, 0x04, 0x7F, 0x02, 0xFE, 0x00, 0x03, 0x14,
+		  0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		  0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
+	PHYREGS(0x0209, 0xFE08, 0xFA08, 0xC701, 0xC801, 0xC801),
+  },
+  {	.channel		= 152,
+	.freq			= 5760, /* MHz */
+	.unk2			= 3840,
+	RADIOREGS(0x71, 0x02, 0x40, 0x02, 0x0A, 0x01, 0x04, 0x0A,
+		  0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		  0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
+	PHYREGS(0x0409, 0x0009, 0xFC08, 0xC601, 0xC701, 0xC801),
+  },
+  {	.channel		= 153,
+	.freq			= 5765, /* MHz */
+	.unk2			= 3843,
+	RADIOREGS(0x72, 0x04, 0x81, 0x02, 0xF8, 0x00, 0x03, 0x14,
+		  0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		  0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
+	PHYREGS(0x0609, 0x0209, 0xFE08, 0xC601, 0xC701, 0xC801),
+  },
+  {	.channel		= 154,
+	.freq			= 5770, /* MHz */
+	.unk2			= 3847,
+	RADIOREGS(0x71, 0x02, 0x41, 0x02, 0x0A, 0x01, 0x04, 0x0A,
+		  0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		  0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
+	PHYREGS(0x0809, 0x0409, 0x0009, 0xC601, 0xC601, 0xC701),
+  },
+  {	.channel		= 155,
+	.freq			= 5775, /* MHz */
+	.unk2			= 3850,
+	RADIOREGS(0x72, 0x04, 0x83, 0x02, 0xF8, 0x00, 0x03, 0x14,
+		  0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		  0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
+	PHYREGS(0x0A09, 0x0609, 0x0209, 0xC501, 0xC601, 0xC701),
+  },
+  {	.channel		= 156,
+	.freq			= 5780, /* MHz */
+	.unk2			= 3853,
+	RADIOREGS(0x71, 0x02, 0x42, 0x02, 0x0A, 0x01, 0x04, 0x0A,
+		  0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		  0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
+	PHYREGS(0x0C09, 0x0809, 0x0409, 0xC501, 0xC601, 0xC601),
+  },
+  {	.channel		= 157,
+	.freq			= 5785, /* MHz */
+	.unk2			= 3857,
+	RADIOREGS(0x72, 0x04, 0x85, 0x02, 0xF2, 0x00, 0x03, 0x14,
+		  0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		  0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
+	PHYREGS(0x0E09, 0x0A09, 0x0609, 0xC401, 0xC501, 0xC601),
+  },
+  {	.channel		= 158,
+	.freq			= 5790, /* MHz */
+	.unk2			= 3860,
+	RADIOREGS(0x71, 0x02, 0x43, 0x02, 0x0A, 0x01, 0x04, 0x0A,
+		  0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		  0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
+	PHYREGS(0x1009, 0x0C09, 0x0809, 0xC401, 0xC501, 0xC601),
+  },
+  {	.channel		= 159,
+	.freq			= 5795, /* MHz */
+	.unk2			= 3863,
+	RADIOREGS(0x72, 0x04, 0x87, 0x02, 0xF2, 0x00, 0x03, 0x14,
+		  0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		  0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
+	PHYREGS(0x1209, 0x0E09, 0x0A09, 0xC401, 0xC401, 0xC501),
+  },
+  {	.channel		= 160,
+	.freq			= 5800, /* MHz */
+	.unk2			= 3867,
+	RADIOREGS(0x71, 0x02, 0x44, 0x01, 0x0A, 0x01, 0x04, 0x0A,
+		  0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		  0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
+	PHYREGS(0x1409, 0x1009, 0x0C09, 0xC301, 0xC401, 0xC501),
+  },
+  {	.channel		= 161,
+	.freq			= 5805, /* MHz */
+	.unk2			= 3870,
+	RADIOREGS(0x72, 0x04, 0x89, 0x01, 0xED, 0x00, 0x03, 0x14,
+		  0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		  0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
+	PHYREGS(0x1609, 0x1209, 0x0E09, 0xC301, 0xC401, 0xC401),
+  },
+  {	.channel		= 162,
+	.freq			= 5810, /* MHz */
+	.unk2			= 3873,
+	RADIOREGS(0x71, 0x02, 0x45, 0x01, 0x0A, 0x01, 0x04, 0x0A,
+		  0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		  0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
+	PHYREGS(0x1809, 0x1409, 0x1009, 0xC201, 0xC301, 0xC401),
+  },
+  {	.channel		= 163,
+	.freq			= 5815, /* MHz */
+	.unk2			= 3877,
+	RADIOREGS(0x72, 0x04, 0x8B, 0x01, 0xED, 0x00, 0x03, 0x14,
+		  0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		  0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
+	PHYREGS(0x1A09, 0x1609, 0x1209, 0xC201, 0xC301, 0xC401),
+  },
+  {	.channel		= 164,
+	.freq			= 5820, /* MHz */
+	.unk2			= 3880,
+	RADIOREGS(0x71, 0x02, 0x46, 0x01, 0x0A, 0x01, 0x04, 0x0A,
+		  0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		  0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
+	PHYREGS(0x1C09, 0x1809, 0x1409, 0xC201, 0xC201, 0xC301),
+  },
+  {	.channel		= 165,
+	.freq			= 5825, /* MHz */
+	.unk2			= 3883,
+	RADIOREGS(0x72, 0x04, 0x8D, 0x01, 0xED, 0x00, 0x03, 0x14,
+		  0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		  0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
+	PHYREGS(0x1E09, 0x1A09, 0x1609, 0xC101, 0xC201, 0xC301),
+  },
+  {	.channel		= 166,
+	.freq			= 5830, /* MHz */
+	.unk2			= 3887,
+	RADIOREGS(0x71, 0x02, 0x47, 0x01, 0x0A, 0x01, 0x04, 0x0A,
+		  0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		  0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
+	PHYREGS(0x2009, 0x1C09, 0x1809, 0xC101, 0xC201, 0xC201),
+  },
+  {	.channel		= 168,
+	.freq			= 5840, /* MHz */
+	.unk2			= 3893,
+	RADIOREGS(0x71, 0x02, 0x48, 0x01, 0x0A, 0x01, 0x04, 0x0A,
+		  0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		  0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
+	PHYREGS(0x2409, 0x2009, 0x1C09, 0xC001, 0xC101, 0xC201),
+  },
+  {	.channel		= 170,
+	.freq			= 5850, /* MHz */
+	.unk2			= 3900,
+	RADIOREGS(0x71, 0x02, 0x49, 0x01, 0xE0, 0x00, 0x04, 0x0A,
+		  0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		  0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
+	PHYREGS(0x2809, 0x2409, 0x2009, 0xBF01, 0xC001, 0xC101),
+  },
+  {	.channel		= 172,
+	.freq			= 5860, /* MHz */
+	.unk2			= 3907,
+	RADIOREGS(0x71, 0x02, 0x4A, 0x01, 0xDE, 0x00, 0x04, 0x0A,
+		  0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		  0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
+	PHYREGS(0x2C09, 0x2809, 0x2409, 0xBF01, 0xBF01, 0xC001),
+  },
+  {	.channel		= 174,
+	.freq			= 5870, /* MHz */
+	.unk2			= 3913,
+	RADIOREGS(0x71, 0x02, 0x4B, 0x00, 0xDB, 0x00, 0x04, 0x0A,
+		  0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		  0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
+	PHYREGS(0x3009, 0x2C09, 0x2809, 0xBE01, 0xBF01, 0xBF01),
+  },
+  {	.channel		= 176,
+	.freq			= 5880, /* MHz */
+	.unk2			= 3920,
+	RADIOREGS(0x71, 0x02, 0x4C, 0x00, 0xD8, 0x00, 0x04, 0x0A,
+		  0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		  0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
+	PHYREGS(0x3409, 0x3009, 0x2C09, 0xBD01, 0xBE01, 0xBF01),
+  },
+  {	.channel		= 178,
+	.freq			= 5890, /* MHz */
+	.unk2			= 3927,
+	RADIOREGS(0x71, 0x02, 0x4D, 0x00, 0xD6, 0x00, 0x04, 0x0A,
+		  0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		  0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
+	PHYREGS(0x3809, 0x3409, 0x3009, 0xBC01, 0xBD01, 0xBE01),
+  },
+  {	.channel		= 180,
+	.freq			= 5900, /* MHz */
+	.unk2			= 3933,
+	RADIOREGS(0x71, 0x02, 0x4E, 0x00, 0xD3, 0x00, 0x04, 0x0A,
+		  0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		  0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
+	PHYREGS(0x3C09, 0x3809, 0x3409, 0xBC01, 0xBC01, 0xBD01),
+  },
+  {	.channel		= 182,
+	.freq			= 5910, /* MHz */
+	.unk2			= 3940,
+	RADIOREGS(0x71, 0x02, 0x4F, 0x00, 0xD6, 0x00, 0x04, 0x0A,
+		  0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		  0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
+	PHYREGS(0x4009, 0x3C09, 0x3809, 0xBB01, 0xBC01, 0xBC01),
+  },
+  {	.channel		= 1,
+	.freq			= 2412, /* MHz */
+	.unk2			= 3216,
+	RADIOREGS(0x73, 0x09, 0x6C, 0x0F, 0x00, 0x01, 0x07, 0x15,
+		  0x01, 0x8F, 0xFF, 0xFF, 0xFF, 0x88, 0x0D, 0x0C,
+		  0x80, 0xFF, 0x88, 0x0D, 0x0C, 0x80),
+	PHYREGS(0xC903, 0xC503, 0xC103, 0x3A04, 0x3F04, 0x4304),
+  },
+  {	.channel		= 2,
+	.freq			= 2417, /* MHz */
+	.unk2			= 3223,
+	RADIOREGS(0x73, 0x09, 0x71, 0x0F, 0x00, 0x01, 0x07, 0x15,
+		  0x01, 0x8F, 0xFF, 0xFF, 0xFF, 0x88, 0x0C, 0x0B,
+		  0x80, 0xFF, 0x88, 0x0C, 0x0B, 0x80),
+	PHYREGS(0xCB03, 0xC703, 0xC303, 0x3804, 0x3D04, 0x4104),
+  },
+  {	.channel		= 3,
+	.freq			= 2422, /* MHz */
+	.unk2			= 3229,
+	RADIOREGS(0x73, 0x09, 0x76, 0x0F, 0x00, 0x01, 0x07, 0x15,
+		  0x01, 0x8F, 0xFF, 0xFF, 0xFF, 0x88, 0x0C, 0x0A,
+		  0x80, 0xFF, 0x88, 0x0C, 0x0A, 0x80),
+	PHYREGS(0xCD03, 0xC903, 0xC503, 0x3604, 0x3A04, 0x3F04),
+  },
+  {	.channel		= 4,
+	.freq			= 2427, /* MHz */
+	.unk2			= 3236,
+	RADIOREGS(0x73, 0x09, 0x7B, 0x0F, 0x00, 0x01, 0x07, 0x15,
+		  0x01, 0x8F, 0xFF, 0xFF, 0xFF, 0x88, 0x0C, 0x0A,
+		  0x80, 0xFF, 0x88, 0x0C, 0x0A, 0x80),
+	PHYREGS(0xCF03, 0xCB03, 0xC703, 0x3404, 0x3804, 0x3D04),
+  },
+  {	.channel		= 5,
+	.freq			= 2432, /* MHz */
+	.unk2			= 3243,
+	RADIOREGS(0x73, 0x09, 0x80, 0x0F, 0x00, 0x01, 0x07, 0x15,
+		  0x01, 0x8F, 0xFF, 0xFF, 0xFF, 0x88, 0x0C, 0x09,
+		  0x80, 0xFF, 0x88, 0x0C, 0x09, 0x80),
+	PHYREGS(0xD103, 0xCD03, 0xC903, 0x3104, 0x3604, 0x3A04),
+  },
+  {	.channel		= 6,
+	.freq			= 2437, /* MHz */
+	.unk2			= 3249,
+	RADIOREGS(0x73, 0x09, 0x85, 0x0F, 0x00, 0x01, 0x07, 0x15,
+		  0x01, 0x8F, 0xFF, 0xFF, 0xFF, 0x88, 0x0B, 0x08,
+		  0x80, 0xFF, 0x88, 0x0B, 0x08, 0x80),
+	PHYREGS(0xD303, 0xCF03, 0xCB03, 0x2F04, 0x3404, 0x3804),
+  },
+  {	.channel		= 7,
+	.freq			= 2442, /* MHz */
+	.unk2			= 3256,
+	RADIOREGS(0x73, 0x09, 0x8A, 0x0F, 0x00, 0x01, 0x07, 0x15,
+		  0x01, 0x8F, 0xFF, 0xFF, 0xFF, 0x88, 0x0A, 0x07,
+		  0x80, 0xFF, 0x88, 0x0A, 0x07, 0x80),
+	PHYREGS(0xD503, 0xD103, 0xCD03, 0x2D04, 0x3104, 0x3604),
+  },
+  {	.channel		= 8,
+	.freq			= 2447, /* MHz */
+	.unk2			= 3263,
+	RADIOREGS(0x73, 0x09, 0x8F, 0x0F, 0x00, 0x01, 0x07, 0x15,
+		  0x01, 0x8F, 0xFF, 0xFF, 0xFF, 0x88, 0x0A, 0x06,
+		  0x80, 0xFF, 0x88, 0x0A, 0x06, 0x80),
+	PHYREGS(0xD703, 0xD303, 0xCF03, 0x2B04, 0x2F04, 0x3404),
+  },
+  {	.channel		= 9,
+	.freq			= 2452, /* MHz */
+	.unk2			= 3269,
+	RADIOREGS(0x73, 0x09, 0x94, 0x0F, 0x00, 0x01, 0x07, 0x15,
+		  0x01, 0x8F, 0xFF, 0xFF, 0xFF, 0x88, 0x09, 0x06,
+		  0x80, 0xFF, 0x88, 0x09, 0x06, 0x80),
+	PHYREGS(0xD903, 0xD503, 0xD103, 0x2904, 0x2D04, 0x3104),
+  },
+  {	.channel		= 10,
+	.freq			= 2457, /* MHz */
+	.unk2			= 3276,
+	RADIOREGS(0x73, 0x09, 0x99, 0x0F, 0x00, 0x01, 0x07, 0x15,
+		  0x01, 0x8F, 0xFF, 0xFF, 0xFF, 0x88, 0x08, 0x05,
+		  0x80, 0xFF, 0x88, 0x08, 0x05, 0x80),
+	PHYREGS(0xDB03, 0xD703, 0xD303, 0x2704, 0x2B04, 0x2F04),
+  },
+  {	.channel		= 11,
+	.freq			= 2462, /* MHz */
+	.unk2			= 3283,
+	RADIOREGS(0x73, 0x09, 0x9E, 0x0F, 0x00, 0x01, 0x07, 0x15,
+		  0x01, 0x8F, 0xFF, 0xFF, 0xFF, 0x88, 0x08, 0x04,
+		  0x80, 0xFF, 0x88, 0x08, 0x04, 0x80),
+	PHYREGS(0xDD03, 0xD903, 0xD503, 0x2404, 0x2904, 0x2D04),
+  },
+  {	.channel		= 12,
+	.freq			= 2467, /* MHz */
+	.unk2			= 3289,
+	RADIOREGS(0x73, 0x09, 0xA3, 0x0F, 0x00, 0x01, 0x07, 0x15,
+		  0x01, 0x8F, 0xFF, 0xFF, 0xFF, 0x88, 0x08, 0x03,
+		  0x80, 0xFF, 0x88, 0x08, 0x03, 0x80),
+	PHYREGS(0xDF03, 0xDB03, 0xD703, 0x2204, 0x2704, 0x2B04),
+  },
+  {	.channel		= 13,
+	.freq			= 2472, /* MHz */
+	.unk2			= 3296,
+	RADIOREGS(0x73, 0x09, 0xA8, 0x0F, 0x00, 0x01, 0x07, 0x15,
+		  0x01, 0x8F, 0xFF, 0xFF, 0xFF, 0x88, 0x07, 0x03,
+		  0x80, 0xFF, 0x88, 0x07, 0x03, 0x80),
+	PHYREGS(0xE103, 0xDD03, 0xD903, 0x2004, 0x2404, 0x2904),
+  },
+  {	.channel		= 14,
+	.freq			= 2484, /* MHz */
+	.unk2			= 3312,
+	RADIOREGS(0x73, 0x09, 0xB4, 0x0F, 0xFF, 0x01, 0x07, 0x15,
+		  0x01, 0x8F, 0xFF, 0xFF, 0xFF, 0x88, 0x07, 0x01,
+		  0x80, 0xFF, 0x88, 0x07, 0x01, 0x80),
+	PHYREGS(0xE603, 0xE203, 0xDE03, 0x1B04, 0x1F04, 0x2404),
+  },
+};
+
+const struct b43_nphy_channeltab_entry *
+b43_nphy_get_chantabent(struct b43_wldev *dev, u8 channel)
+{
+	const struct b43_nphy_channeltab_entry *e;
+	unsigned int i;
+
+	for (i = 0; i < ARRAY_SIZE(b43_nphy_channeltab); i++) {
+		e = &(b43_nphy_channeltab[i]);
+		if (e->channel == channel)
+			return e;
+	}
+
+	return NULL;
+}
+
+
+const u8 b43_ntab_adjustpower0[] = {
+	0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01,
+	0x02, 0x02, 0x02, 0x02, 0x03, 0x03, 0x03, 0x03,
+	0x04, 0x04, 0x04, 0x04, 0x05, 0x05, 0x05, 0x05,
+	0x06, 0x06, 0x06, 0x06, 0x07, 0x07, 0x07, 0x07,
+	0x08, 0x08, 0x08, 0x08, 0x09, 0x09, 0x09, 0x09,
+	0x0A, 0x0A, 0x0A, 0x0A, 0x0B, 0x0B, 0x0B, 0x0B,
+	0x0C, 0x0C, 0x0C, 0x0C, 0x0D, 0x0D, 0x0D, 0x0D,
+	0x0E, 0x0E, 0x0E, 0x0E, 0x0F, 0x0F, 0x0F, 0x0F,
+	0x10, 0x10, 0x10, 0x10, 0x11, 0x11, 0x11, 0x11,
+	0x12, 0x12, 0x12, 0x12, 0x13, 0x13, 0x13, 0x13,
+	0x14, 0x14, 0x14, 0x14, 0x15, 0x15, 0x15, 0x15,
+	0x16, 0x16, 0x16, 0x16, 0x17, 0x17, 0x17, 0x17,
+	0x18, 0x18, 0x18, 0x18, 0x19, 0x19, 0x19, 0x19,
+	0x1A, 0x1A, 0x1A, 0x1A, 0x1B, 0x1B, 0x1B, 0x1B,
+	0x1C, 0x1C, 0x1C, 0x1C, 0x1D, 0x1D, 0x1D, 0x1D,
+	0x1E, 0x1E, 0x1E, 0x1E, 0x1F, 0x1F, 0x1F, 0x1F,
+};
+
+const u8 b43_ntab_adjustpower1[] = {
+	0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01,
+	0x02, 0x02, 0x02, 0x02, 0x03, 0x03, 0x03, 0x03,
+	0x04, 0x04, 0x04, 0x04, 0x05, 0x05, 0x05, 0x05,
+	0x06, 0x06, 0x06, 0x06, 0x07, 0x07, 0x07, 0x07,
+	0x08, 0x08, 0x08, 0x08, 0x09, 0x09, 0x09, 0x09,
+	0x0A, 0x0A, 0x0A, 0x0A, 0x0B, 0x0B, 0x0B, 0x0B,
+	0x0C, 0x0C, 0x0C, 0x0C, 0x0D, 0x0D, 0x0D, 0x0D,
+	0x0E, 0x0E, 0x0E, 0x0E, 0x0F, 0x0F, 0x0F, 0x0F,
+	0x10, 0x10, 0x10, 0x10, 0x11, 0x11, 0x11, 0x11,
+	0x12, 0x12, 0x12, 0x12, 0x13, 0x13, 0x13, 0x13,
+	0x14, 0x14, 0x14, 0x14, 0x15, 0x15, 0x15, 0x15,
+	0x16, 0x16, 0x16, 0x16, 0x17, 0x17, 0x17, 0x17,
+	0x18, 0x18, 0x18, 0x18, 0x19, 0x19, 0x19, 0x19,
+	0x1A, 0x1A, 0x1A, 0x1A, 0x1B, 0x1B, 0x1B, 0x1B,
+	0x1C, 0x1C, 0x1C, 0x1C, 0x1D, 0x1D, 0x1D, 0x1D,
+	0x1E, 0x1E, 0x1E, 0x1E, 0x1F, 0x1F, 0x1F, 0x1F,
+};
+
+const u16 b43_ntab_bdi[] = {
+	0x0070, 0x0126, 0x012C, 0x0246, 0x048D, 0x04D2,
+};
+
+const u32 b43_ntab_channelest[] = {
+	0x44444444, 0x44444444, 0x44444444, 0x44444444,
+	0x44444444, 0x44444444, 0x44444444, 0x44444444,
+	0x10101010, 0x10101010, 0x10101010, 0x10101010,
+	0x10101010, 0x10101010, 0x10101010, 0x10101010,
+	0x44444444, 0x44444444, 0x44444444, 0x44444444,
+	0x44444444, 0x44444444, 0x44444444, 0x44444444,
+	0x10101010, 0x10101010, 0x10101010, 0x10101010,
+	0x10101010, 0x10101010, 0x10101010, 0x10101010,
+	0x44444444, 0x44444444, 0x44444444, 0x44444444,
+	0x44444444, 0x44444444, 0x44444444, 0x44444444,
+	0x44444444, 0x44444444, 0x44444444, 0x44444444,
+	0x44444444, 0x44444444, 0x44444444, 0x44444444,
+	0x10101010, 0x10101010, 0x10101010, 0x10101010,
+	0x10101010, 0x10101010, 0x10101010, 0x10101010,
+	0x10101010, 0x10101010, 0x10101010, 0x10101010,
+	0x10101010, 0x10101010, 0x10101010, 0x10101010,
+	0x44444444, 0x44444444, 0x44444444, 0x44444444,
+	0x44444444, 0x44444444, 0x44444444, 0x44444444,
+	0x44444444, 0x44444444, 0x44444444, 0x44444444,
+	0x44444444, 0x44444444, 0x44444444, 0x44444444,
+	0x10101010, 0x10101010, 0x10101010, 0x10101010,
+	0x10101010, 0x10101010, 0x10101010, 0x10101010,
+	0x10101010, 0x10101010, 0x10101010, 0x10101010,
+	0x10101010, 0x10101010, 0x10101010, 0x10101010,
+};
+
+const u8 b43_ntab_estimatepowerlt0[] = {
+	0x50, 0x4F, 0x4E, 0x4D, 0x4C, 0x4B, 0x4A, 0x49,
+	0x48, 0x47, 0x46, 0x45, 0x44, 0x43, 0x42, 0x41,
+	0x40, 0x3F, 0x3E, 0x3D, 0x3C, 0x3B, 0x3A, 0x39,
+	0x38, 0x37, 0x36, 0x35, 0x34, 0x33, 0x32, 0x31,
+	0x30, 0x2F, 0x2E, 0x2D, 0x2C, 0x2B, 0x2A, 0x29,
+	0x28, 0x27, 0x26, 0x25, 0x24, 0x23, 0x22, 0x21,
+	0x20, 0x1F, 0x1E, 0x1D, 0x1C, 0x1B, 0x1A, 0x19,
+	0x18, 0x17, 0x16, 0x15, 0x14, 0x13, 0x12, 0x11,
+};
+
+const u8 b43_ntab_estimatepowerlt1[] = {
+	0x50, 0x4F, 0x4E, 0x4D, 0x4C, 0x4B, 0x4A, 0x49,
+	0x48, 0x47, 0x46, 0x45, 0x44, 0x43, 0x42, 0x41,
+	0x40, 0x3F, 0x3E, 0x3D, 0x3C, 0x3B, 0x3A, 0x39,
+	0x38, 0x37, 0x36, 0x35, 0x34, 0x33, 0x32, 0x31,
+	0x30, 0x2F, 0x2E, 0x2D, 0x2C, 0x2B, 0x2A, 0x29,
+	0x28, 0x27, 0x26, 0x25, 0x24, 0x23, 0x22, 0x21,
+	0x20, 0x1F, 0x1E, 0x1D, 0x1C, 0x1B, 0x1A, 0x19,
+	0x18, 0x17, 0x16, 0x15, 0x14, 0x13, 0x12, 0x11,
+};
+
+const u8 b43_ntab_framelookup[] = {
+	0x02, 0x04, 0x14, 0x14, 0x03, 0x05, 0x16, 0x16,
+	0x0A, 0x0C, 0x1C, 0x1C, 0x0B, 0x0D, 0x1E, 0x1E,
+	0x06, 0x08, 0x18, 0x18, 0x07, 0x09, 0x1A, 0x1A,
+	0x0E, 0x10, 0x20, 0x28, 0x0F, 0x11, 0x22, 0x2A,
+};
+
+const u32 b43_ntab_framestruct[] = {
+	0x08004A04, 0x00100000, 0x01000A05, 0x00100020,
+	0x09804506, 0x00100030, 0x09804507, 0x00100030,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x08004A0C, 0x00100008, 0x01000A0D, 0x00100028,
+	0x0980450E, 0x00100038, 0x0980450F, 0x00100038,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000A04, 0x00100000, 0x11008A05, 0x00100020,
+	0x1980C506, 0x00100030, 0x21810506, 0x00100030,
+	0x21810506, 0x00100030, 0x01800504, 0x00100030,
+	0x11808505, 0x00100030, 0x29814507, 0x01100030,
+	0x00000A04, 0x00100000, 0x11008A05, 0x00100020,
+	0x21810506, 0x00100030, 0x21810506, 0x00100030,
+	0x29814507, 0x01100030, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000A0C, 0x00100008, 0x11008A0D, 0x00100028,
+	0x1980C50E, 0x00100038, 0x2181050E, 0x00100038,
+	0x2181050E, 0x00100038, 0x0180050C, 0x00100038,
+	0x1180850D, 0x00100038, 0x2981450F, 0x01100038,
+	0x00000A0C, 0x00100008, 0x11008A0D, 0x00100028,
+	0x2181050E, 0x00100038, 0x2181050E, 0x00100038,
+	0x2981450F, 0x01100038, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x08004A04, 0x00100000, 0x01000A05, 0x00100020,
+	0x1980C506, 0x00100030, 0x1980C506, 0x00100030,
+	0x11808504, 0x00100030, 0x3981CA05, 0x00100030,
+	0x29814507, 0x01100030, 0x00000000, 0x00000000,
+	0x10008A04, 0x00100000, 0x3981CA05, 0x00100030,
+	0x1980C506, 0x00100030, 0x29814507, 0x01100030,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x08004A0C, 0x00100008, 0x01000A0D, 0x00100028,
+	0x1980C50E, 0x00100038, 0x1980C50E, 0x00100038,
+	0x1180850C, 0x00100038, 0x3981CA0D, 0x00100038,
+	0x2981450F, 0x01100038, 0x00000000, 0x00000000,
+	0x10008A0C, 0x00100008, 0x3981CA0D, 0x00100038,
+	0x1980C50E, 0x00100038, 0x2981450F, 0x01100038,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x40021404, 0x00100000, 0x02001405, 0x00100040,
+	0x0B004A06, 0x01900060, 0x13008A06, 0x01900060,
+	0x13008A06, 0x01900060, 0x43020A04, 0x00100060,
+	0x1B00CA05, 0x00100060, 0x23010A07, 0x01500060,
+	0x40021404, 0x00100000, 0x1A00D405, 0x00100040,
+	0x13008A06, 0x01900060, 0x13008A06, 0x01900060,
+	0x23010A07, 0x01500060, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x4002140C, 0x00100010, 0x0200140D, 0x00100050,
+	0x0B004A0E, 0x01900070, 0x13008A0E, 0x01900070,
+	0x13008A0E, 0x01900070, 0x43020A0C, 0x00100070,
+	0x1B00CA0D, 0x00100070, 0x23010A0F, 0x01500070,
+	0x4002140C, 0x00100010, 0x1A00D40D, 0x00100050,
+	0x13008A0E, 0x01900070, 0x13008A0E, 0x01900070,
+	0x23010A0F, 0x01500070, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x50029404, 0x00100000, 0x32019405, 0x00100040,
+	0x0B004A06, 0x01900060, 0x0B004A06, 0x01900060,
+	0x5B02CA04, 0x00100060, 0x3B01D405, 0x00100060,
+	0x23010A07, 0x01500060, 0x00000000, 0x00000000,
+	0x5802D404, 0x00100000, 0x3B01D405, 0x00100060,
+	0x0B004A06, 0x01900060, 0x23010A07, 0x01500060,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x5002940C, 0x00100010, 0x3201940D, 0x00100050,
+	0x0B004A0E, 0x01900070, 0x0B004A0E, 0x01900070,
+	0x5B02CA0C, 0x00100070, 0x3B01D40D, 0x00100070,
+	0x23010A0F, 0x01500070, 0x00000000, 0x00000000,
+	0x5802D40C, 0x00100010, 0x3B01D40D, 0x00100070,
+	0x0B004A0E, 0x01900070, 0x23010A0F, 0x01500070,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x40021404, 0x000F4800, 0x62031405, 0x00100040,
+	0x53028A06, 0x01900060, 0x53028A07, 0x01900060,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x4002140C, 0x000F4810, 0x6203140D, 0x00100050,
+	0x53028A0E, 0x01900070, 0x53028A0F, 0x01900070,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000A0C, 0x00100008, 0x11008A0D, 0x00100028,
+	0x1980C50E, 0x00100038, 0x2181050E, 0x00100038,
+	0x2181050E, 0x00100038, 0x0180050C, 0x00100038,
+	0x1180850D, 0x00100038, 0x1181850D, 0x00100038,
+	0x2981450F, 0x01100038, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000A0C, 0x00100008, 0x11008A0D, 0x00100028,
+	0x2181050E, 0x00100038, 0x2181050E, 0x00100038,
+	0x1181850D, 0x00100038, 0x2981450F, 0x01100038,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x08004A04, 0x00100000, 0x01000A05, 0x00100020,
+	0x0180C506, 0x00100030, 0x0180C506, 0x00100030,
+	0x2180C50C, 0x00100030, 0x49820A0D, 0x0016A130,
+	0x41824A0D, 0x0016A130, 0x2981450F, 0x01100030,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x2000CA0C, 0x00100000, 0x49820A0D, 0x0016A130,
+	0x1980C50E, 0x00100030, 0x41824A0D, 0x0016A130,
+	0x2981450F, 0x01100030, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x4002140C, 0x00100010, 0x0200140D, 0x00100050,
+	0x0B004A0E, 0x01900070, 0x13008A0E, 0x01900070,
+	0x13008A0E, 0x01900070, 0x43020A0C, 0x00100070,
+	0x1B00CA0D, 0x00100070, 0x1B014A0D, 0x00100070,
+	0x23010A0F, 0x01500070, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x4002140C, 0x00100010, 0x1A00D40D, 0x00100050,
+	0x13008A0E, 0x01900070, 0x13008A0E, 0x01900070,
+	0x1B014A0D, 0x00100070, 0x23010A0F, 0x01500070,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x50029404, 0x00100000, 0x32019405, 0x00100040,
+	0x03004A06, 0x01900060, 0x03004A06, 0x01900060,
+	0x6B030A0C, 0x00100060, 0x4B02140D, 0x0016A160,
+	0x4302540D, 0x0016A160, 0x23010A0F, 0x01500060,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x6B03140C, 0x00100060, 0x4B02140D, 0x0016A160,
+	0x0B004A0E, 0x01900060, 0x4302540D, 0x0016A160,
+	0x23010A0F, 0x01500060, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x40021404, 0x00100000, 0x1A00D405, 0x00100040,
+	0x53028A06, 0x01900060, 0x5B02CA06, 0x01900060,
+	0x5B02CA06, 0x01900060, 0x43020A04, 0x00100060,
+	0x1B00CA05, 0x00100060, 0x53028A07, 0x0190C060,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x4002140C, 0x00100010, 0x1A00D40D, 0x00100050,
+	0x53028A0E, 0x01900070, 0x5B02CA0E, 0x01900070,
+	0x5B02CA0E, 0x01900070, 0x43020A0C, 0x00100070,
+	0x1B00CA0D, 0x00100070, 0x53028A0F, 0x0190C070,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x40021404, 0x00100000, 0x1A00D405, 0x00100040,
+	0x5B02CA06, 0x01900060, 0x5B02CA06, 0x01900060,
+	0x53028A07, 0x0190C060, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x4002140C, 0x00100010, 0x1A00D40D, 0x00100050,
+	0x5B02CA0E, 0x01900070, 0x5B02CA0E, 0x01900070,
+	0x53028A0F, 0x0190C070, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+};
+
+const u32 b43_ntab_gainctl0[] = {
+	0x007F003F, 0x007E013F, 0x007D023E, 0x007C033E,
+	0x007B043D, 0x007A053D, 0x0079063C, 0x0078073C,
+	0x0077083B, 0x0076093B, 0x00750A3A, 0x00740B3A,
+	0x00730C39, 0x00720D39, 0x00710E38, 0x00700F38,
+	0x006F0037, 0x006E0137, 0x006D0236, 0x006C0336,
+	0x006B0435, 0x006A0535, 0x00690634, 0x00680734,
+	0x00670833, 0x00660933, 0x00650A32, 0x00640B32,
+	0x00630C31, 0x00620D31, 0x00610E30, 0x00600F30,
+	0x005F002F, 0x005E012F, 0x005D022E, 0x005C032E,
+	0x005B042D, 0x005A052D, 0x0059062C, 0x0058072C,
+	0x0057082B, 0x0056092B, 0x00550A2A, 0x00540B2A,
+	0x00530C29, 0x00520D29, 0x00510E28, 0x00500F28,
+	0x004F0027, 0x004E0127, 0x004D0226, 0x004C0326,
+	0x004B0425, 0x004A0525, 0x00490624, 0x00480724,
+	0x00470823, 0x00460923, 0x00450A22, 0x00440B22,
+	0x00430C21, 0x00420D21, 0x00410E20, 0x00400F20,
+	0x003F001F, 0x003E011F, 0x003D021E, 0x003C031E,
+	0x003B041D, 0x003A051D, 0x0039061C, 0x0038071C,
+	0x0037081B, 0x0036091B, 0x00350A1A, 0x00340B1A,
+	0x00330C19, 0x00320D19, 0x00310E18, 0x00300F18,
+	0x002F0017, 0x002E0117, 0x002D0216, 0x002C0316,
+	0x002B0415, 0x002A0515, 0x00290614, 0x00280714,
+	0x00270813, 0x00260913, 0x00250A12, 0x00240B12,
+	0x00230C11, 0x00220D11, 0x00210E10, 0x00200F10,
+	0x001F000F, 0x001E010F, 0x001D020E, 0x001C030E,
+	0x001B040D, 0x001A050D, 0x0019060C, 0x0018070C,
+	0x0017080B, 0x0016090B, 0x00150A0A, 0x00140B0A,
+	0x00130C09, 0x00120D09, 0x00110E08, 0x00100F08,
+	0x000F0007, 0x000E0107, 0x000D0206, 0x000C0306,
+	0x000B0405, 0x000A0505, 0x00090604, 0x00080704,
+	0x00070803, 0x00060903, 0x00050A02, 0x00040B02,
+	0x00030C01, 0x00020D01, 0x00010E00, 0x00000F00,
+};
+
+const u32 b43_ntab_gainctl1[] = {
+	0x007F003F, 0x007E013F, 0x007D023E, 0x007C033E,
+	0x007B043D, 0x007A053D, 0x0079063C, 0x0078073C,
+	0x0077083B, 0x0076093B, 0x00750A3A, 0x00740B3A,
+	0x00730C39, 0x00720D39, 0x00710E38, 0x00700F38,
+	0x006F0037, 0x006E0137, 0x006D0236, 0x006C0336,
+	0x006B0435, 0x006A0535, 0x00690634, 0x00680734,
+	0x00670833, 0x00660933, 0x00650A32, 0x00640B32,
+	0x00630C31, 0x00620D31, 0x00610E30, 0x00600F30,
+	0x005F002F, 0x005E012F, 0x005D022E, 0x005C032E,
+	0x005B042D, 0x005A052D, 0x0059062C, 0x0058072C,
+	0x0057082B, 0x0056092B, 0x00550A2A, 0x00540B2A,
+	0x00530C29, 0x00520D29, 0x00510E28, 0x00500F28,
+	0x004F0027, 0x004E0127, 0x004D0226, 0x004C0326,
+	0x004B0425, 0x004A0525, 0x00490624, 0x00480724,
+	0x00470823, 0x00460923, 0x00450A22, 0x00440B22,
+	0x00430C21, 0x00420D21, 0x00410E20, 0x00400F20,
+	0x003F001F, 0x003E011F, 0x003D021E, 0x003C031E,
+	0x003B041D, 0x003A051D, 0x0039061C, 0x0038071C,
+	0x0037081B, 0x0036091B, 0x00350A1A, 0x00340B1A,
+	0x00330C19, 0x00320D19, 0x00310E18, 0x00300F18,
+	0x002F0017, 0x002E0117, 0x002D0216, 0x002C0316,
+	0x002B0415, 0x002A0515, 0x00290614, 0x00280714,
+	0x00270813, 0x00260913, 0x00250A12, 0x00240B12,
+	0x00230C11, 0x00220D11, 0x00210E10, 0x00200F10,
+	0x001F000F, 0x001E010F, 0x001D020E, 0x001C030E,
+	0x001B040D, 0x001A050D, 0x0019060C, 0x0018070C,
+	0x0017080B, 0x0016090B, 0x00150A0A, 0x00140B0A,
+	0x00130C09, 0x00120D09, 0x00110E08, 0x00100F08,
+	0x000F0007, 0x000E0107, 0x000D0206, 0x000C0306,
+	0x000B0405, 0x000A0505, 0x00090604, 0x00080704,
+	0x00070803, 0x00060903, 0x00050A02, 0x00040B02,
+	0x00030C01, 0x00020D01, 0x00010E00, 0x00000F00,
+};
+
+const u32 b43_ntab_intlevel[] = {
+	0x00802070, 0x0671188D, 0x0A60192C, 0x0A300E46,
+	0x00C1188D, 0x080024D2, 0x00000070,
+};
+
+const u32 b43_ntab_iqlt0[] = {
+	0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F,
+	0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F,
+	0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F,
+	0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F,
+	0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F,
+	0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F,
+	0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F,
+	0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F,
+	0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F,
+	0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F,
+	0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F,
+	0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F,
+	0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F,
+	0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F,
+	0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F,
+	0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F,
+	0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F,
+	0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F,
+	0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F,
+	0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F,
+	0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F,
+	0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F,
+	0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F,
+	0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F,
+	0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F,
+	0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F,
+	0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F,
+	0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F,
+	0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F,
+	0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F,
+	0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F,
+	0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F,
+};
+
+const u32 b43_ntab_iqlt1[] = {
+	0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F,
+	0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F,
+	0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F,
+	0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F,
+	0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F,
+	0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F,
+	0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F,
+	0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F,
+	0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F,
+	0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F,
+	0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F,
+	0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F,
+	0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F,
+	0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F,
+	0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F,
+	0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F,
+	0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F,
+	0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F,
+	0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F,
+	0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F,
+	0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F,
+	0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F,
+	0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F,
+	0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F,
+	0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F,
+	0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F,
+	0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F,
+	0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F,
+	0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F,
+	0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F,
+	0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F,
+	0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F,
+};
+
+const u16 b43_ntab_loftlt0[] = {
+	0x0000, 0x0101, 0x0002, 0x0103, 0x0000, 0x0101,
+	0x0002, 0x0103, 0x0000, 0x0101, 0x0002, 0x0103,
+	0x0000, 0x0101, 0x0002, 0x0103, 0x0000, 0x0101,
+	0x0002, 0x0103, 0x0000, 0x0101, 0x0002, 0x0103,
+	0x0000, 0x0101, 0x0002, 0x0103, 0x0000, 0x0101,
+	0x0002, 0x0103, 0x0000, 0x0101, 0x0002, 0x0103,
+	0x0000, 0x0101, 0x0002, 0x0103, 0x0000, 0x0101,
+	0x0002, 0x0103, 0x0000, 0x0101, 0x0002, 0x0103,
+	0x0000, 0x0101, 0x0002, 0x0103, 0x0000, 0x0101,
+	0x0002, 0x0103, 0x0000, 0x0101, 0x0002, 0x0103,
+	0x0000, 0x0101, 0x0002, 0x0103, 0x0000, 0x0101,
+	0x0002, 0x0103, 0x0000, 0x0101, 0x0002, 0x0103,
+	0x0000, 0x0101, 0x0002, 0x0103, 0x0000, 0x0101,
+	0x0002, 0x0103, 0x0000, 0x0101, 0x0002, 0x0103,
+	0x0000, 0x0101, 0x0002, 0x0103, 0x0000, 0x0101,
+	0x0002, 0x0103, 0x0000, 0x0101, 0x0002, 0x0103,
+	0x0000, 0x0101, 0x0002, 0x0103, 0x0000, 0x0101,
+	0x0002, 0x0103, 0x0000, 0x0101, 0x0002, 0x0103,
+	0x0000, 0x0101, 0x0002, 0x0103, 0x0000, 0x0101,
+	0x0002, 0x0103, 0x0000, 0x0101, 0x0002, 0x0103,
+	0x0000, 0x0101, 0x0002, 0x0103, 0x0000, 0x0101,
+	0x0002, 0x0103,
+};
+
+const u16 b43_ntab_loftlt1[] = {
+	0x0000, 0x0101, 0x0002, 0x0103, 0x0000, 0x0101,
+	0x0002, 0x0103, 0x0000, 0x0101, 0x0002, 0x0103,
+	0x0000, 0x0101, 0x0002, 0x0103, 0x0000, 0x0101,
+	0x0002, 0x0103, 0x0000, 0x0101, 0x0002, 0x0103,
+	0x0000, 0x0101, 0x0002, 0x0103, 0x0000, 0x0101,
+	0x0002, 0x0103, 0x0000, 0x0101, 0x0002, 0x0103,
+	0x0000, 0x0101, 0x0002, 0x0103, 0x0000, 0x0101,
+	0x0002, 0x0103, 0x0000, 0x0101, 0x0002, 0x0103,
+	0x0000, 0x0101, 0x0002, 0x0103, 0x0000, 0x0101,
+	0x0002, 0x0103, 0x0000, 0x0101, 0x0002, 0x0103,
+	0x0000, 0x0101, 0x0002, 0x0103, 0x0000, 0x0101,
+	0x0002, 0x0103, 0x0000, 0x0101, 0x0002, 0x0103,
+	0x0000, 0x0101, 0x0002, 0x0103, 0x0000, 0x0101,
+	0x0002, 0x0103, 0x0000, 0x0101, 0x0002, 0x0103,
+	0x0000, 0x0101, 0x0002, 0x0103, 0x0000, 0x0101,
+	0x0002, 0x0103, 0x0000, 0x0101, 0x0002, 0x0103,
+	0x0000, 0x0101, 0x0002, 0x0103, 0x0000, 0x0101,
+	0x0002, 0x0103, 0x0000, 0x0101, 0x0002, 0x0103,
+	0x0000, 0x0101, 0x0002, 0x0103, 0x0000, 0x0101,
+	0x0002, 0x0103, 0x0000, 0x0101, 0x0002, 0x0103,
+	0x0000, 0x0101, 0x0002, 0x0103, 0x0000, 0x0101,
+	0x0002, 0x0103,
+};
+
+const u8 b43_ntab_mcs[] = {
+	0x00, 0x08, 0x0A, 0x10, 0x12, 0x19, 0x1A, 0x1C,
+	0x40, 0x48, 0x4A, 0x50, 0x52, 0x59, 0x5A, 0x5C,
+	0x80, 0x88, 0x8A, 0x90, 0x92, 0x99, 0x9A, 0x9C,
+	0xC0, 0xC8, 0xCA, 0xD0, 0xD2, 0xD9, 0xDA, 0xDC,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x01, 0x02, 0x04, 0x08, 0x09, 0x0A, 0x0C,
+	0x10, 0x11, 0x12, 0x14, 0x18, 0x19, 0x1A, 0x1C,
+	0x20, 0x21, 0x22, 0x24, 0x40, 0x41, 0x42, 0x44,
+	0x48, 0x49, 0x4A, 0x4C, 0x50, 0x51, 0x52, 0x54,
+	0x58, 0x59, 0x5A, 0x5C, 0x60, 0x61, 0x62, 0x64,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+};
+
+const u32 b43_ntab_noisevar10[] = {
+	0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+	0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+	0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+	0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+	0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+	0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+	0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+	0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+	0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+	0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+	0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+	0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+	0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+	0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+	0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+	0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+	0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+	0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+	0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+	0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+	0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+	0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+	0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+	0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+	0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+	0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+	0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+	0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+	0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+	0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+	0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+	0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+	0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+	0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+	0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+	0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+	0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+	0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+	0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+	0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+	0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+	0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+	0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+	0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+	0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+	0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+	0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+	0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+	0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+	0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+	0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+	0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+	0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+	0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+	0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+	0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+	0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+	0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+	0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+	0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+	0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+	0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+	0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+	0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+};
+
+const u32 b43_ntab_noisevar11[] = {
+	0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+	0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+	0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+	0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+	0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+	0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+	0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+	0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+	0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+	0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+	0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+	0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+	0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+	0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+	0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+	0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+	0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+	0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+	0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+	0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+	0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+	0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+	0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+	0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+	0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+	0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+	0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+	0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+	0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+	0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+	0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+	0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+	0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+	0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+	0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+	0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+	0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+	0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+	0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+	0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+	0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+	0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+	0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+	0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+	0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+	0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+	0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+	0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+	0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+	0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+	0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+	0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+	0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+	0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+	0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+	0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+	0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+	0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+	0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+	0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+	0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+	0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+	0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+	0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+};
+
+const u16 b43_ntab_pilot[] = {
+	0xFF08, 0xFF08, 0xFF08, 0xFF08, 0xFF08, 0xFF08,
+	0xFF08, 0xFF08, 0x80D5, 0x80D5, 0x80D5, 0x80D5,
+	0x80D5, 0x80D5, 0x80D5, 0x80D5, 0xFF0A, 0xFF82,
+	0xFFA0, 0xFF28, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
+	0xFF82, 0xFFA0, 0xFF28, 0xFF0A, 0xFFFF, 0xFFFF,
+	0xFFFF, 0xFFFF, 0xF83F, 0xFA1F, 0xFA97, 0xFAB5,
+	0xF2BD, 0xF0BF, 0xFFFF, 0xFFFF, 0xF017, 0xF815,
+	0xF215, 0xF095, 0xF035, 0xF01D, 0xFFFF, 0xFFFF,
+	0xFF08, 0xFF02, 0xFF80, 0xFF20, 0xFF08, 0xFF02,
+	0xFF80, 0xFF20, 0xF01F, 0xF817, 0xFA15, 0xF295,
+	0xF0B5, 0xF03D, 0xFFFF, 0xFFFF, 0xF82A, 0xFA0A,
+	0xFA82, 0xFAA0, 0xF2A8, 0xF0AA, 0xFFFF, 0xFFFF,
+	0xF002, 0xF800, 0xF200, 0xF080, 0xF020, 0xF008,
+	0xFFFF, 0xFFFF, 0xF00A, 0xF802, 0xFA00, 0xF280,
+	0xF0A0, 0xF028, 0xFFFF, 0xFFFF,
+};
+
+const u32 b43_ntab_pilotlt[] = {
+	0x76540123, 0x62407351, 0x76543201, 0x76540213,
+	0x76540123, 0x76430521,
+};
+
+const u32 b43_ntab_tdi20a0[] = {
+	0x00091226, 0x000A1429, 0x000B56AD, 0x000C58B0,
+	0x000D5AB3, 0x000E9CB6, 0x000F9EBA, 0x0000C13D,
+	0x00020301, 0x00030504, 0x00040708, 0x0005090B,
+	0x00064B8E, 0x00095291, 0x000A5494, 0x000B9718,
+	0x000C9927, 0x000D9B2A, 0x000EDD2E, 0x000FDF31,
+	0x000101B4, 0x000243B7, 0x000345BB, 0x000447BE,
+	0x00058982, 0x00068C05, 0x00099309, 0x000A950C,
+	0x000BD78F, 0x000CD992, 0x000DDB96, 0x000F1D99,
+	0x00005FA8, 0x0001422C, 0x0002842F, 0x00038632,
+	0x00048835, 0x0005CA38, 0x0006CCBC, 0x0009D3BF,
+	0x000B1603, 0x000C1806, 0x000D1A0A, 0x000E1C0D,
+	0x000F5E10, 0x00008093, 0x00018297, 0x0002C49A,
+	0x0003C680, 0x0004C880, 0x00060B00, 0x00070D00,
+	0x00000000, 0x00000000, 0x00000000,
+};
+
+const u32 b43_ntab_tdi20a1[] = {
+	0x00014B26, 0x00028D29, 0x000393AD, 0x00049630,
+	0x0005D833, 0x0006DA36, 0x00099C3A, 0x000A9E3D,
+	0x000BC081, 0x000CC284, 0x000DC488, 0x000F068B,
+	0x0000488E, 0x00018B91, 0x0002D214, 0x0003D418,
+	0x0004D6A7, 0x000618AA, 0x00071AAE, 0x0009DCB1,
+	0x000B1EB4, 0x000C0137, 0x000D033B, 0x000E053E,
+	0x000F4702, 0x00008905, 0x00020C09, 0x0003128C,
+	0x0004148F, 0x00051712, 0x00065916, 0x00091B19,
+	0x000A1D28, 0x000B5F2C, 0x000C41AF, 0x000D43B2,
+	0x000E85B5, 0x000F87B8, 0x0000C9BC, 0x00024CBF,
+	0x00035303, 0x00045506, 0x0005978A, 0x0006998D,
+	0x00095B90, 0x000A5D93, 0x000B9F97, 0x000C821A,
+	0x000D8400, 0x000EC600, 0x000FC800, 0x00010A00,
+	0x00000000, 0x00000000, 0x00000000,
+};
+
+const u32 b43_ntab_tdi40a0[] = {
+	0x0011A346, 0x00136CCF, 0x0014F5D9, 0x001641E2,
+	0x0017CB6B, 0x00195475, 0x001B2383, 0x001CAD0C,
+	0x001E7616, 0x0000821F, 0x00020BA8, 0x0003D4B2,
+	0x00056447, 0x00072DD0, 0x0008B6DA, 0x000A02E3,
+	0x000B8C6C, 0x000D15F6, 0x0011E484, 0x0013AE0D,
+	0x00153717, 0x00168320, 0x00180CA9, 0x00199633,
+	0x001B6548, 0x001CEED1, 0x001EB7DB, 0x0000C3E4,
+	0x00024D6D, 0x000416F7, 0x0005A585, 0x00076F0F,
+	0x0008F818, 0x000A4421, 0x000BCDAB, 0x000D9734,
+	0x00122649, 0x0013EFD2, 0x001578DC, 0x0016C4E5,
+	0x00184E6E, 0x001A17F8, 0x001BA686, 0x001D3010,
+	0x001EF999, 0x00010522, 0x00028EAC, 0x00045835,
+	0x0005E74A, 0x0007B0D3, 0x00093A5D, 0x000A85E6,
+	0x000C0F6F, 0x000DD8F9, 0x00126787, 0x00143111,
+	0x0015BA9A, 0x00170623, 0x00188FAD, 0x001A5936,
+	0x001BE84B, 0x001DB1D4, 0x001F3B5E, 0x000146E7,
+	0x00031070, 0x000499FA, 0x00062888, 0x0007F212,
+	0x00097B9B, 0x000AC7A4, 0x000C50AE, 0x000E1A37,
+	0x0012A94C, 0x001472D5, 0x0015FC5F, 0x00174868,
+	0x0018D171, 0x001A9AFB, 0x001C2989, 0x001DF313,
+	0x001F7C9C, 0x000188A5, 0x000351AF, 0x0004DB38,
+	0x0006AA4D, 0x000833D7, 0x0009BD60, 0x000B0969,
+	0x000C9273, 0x000E5BFC, 0x00132A8A, 0x0014B414,
+	0x00163D9D, 0x001789A6, 0x001912B0, 0x001ADC39,
+	0x001C6BCE, 0x001E34D8, 0x001FBE61, 0x0001CA6A,
+	0x00039374, 0x00051CFD, 0x0006EC0B, 0x00087515,
+	0x0009FE9E, 0x000B4AA7, 0x000CD3B1, 0x000E9D3A,
+	0x00000000, 0x00000000,
+};
+
+const u32 b43_ntab_tdi40a1[] = {
+	0x001EDB36, 0x000129CA, 0x0002B353, 0x00047CDD,
+	0x0005C8E6, 0x000791EF, 0x00091BF9, 0x000AAA07,
+	0x000C3391, 0x000DFD1A, 0x00120923, 0x0013D22D,
+	0x00155C37, 0x0016EACB, 0x00187454, 0x001A3DDE,
+	0x001B89E7, 0x001D12F0, 0x001F1CFA, 0x00016B88,
+	0x00033492, 0x0004BE1B, 0x00060A24, 0x0007D32E,
+	0x00095D38, 0x000AEC4C, 0x000C7555, 0x000E3EDF,
+	0x00124AE8, 0x001413F1, 0x0015A37B, 0x00172C89,
+	0x0018B593, 0x001A419C, 0x001BCB25, 0x001D942F,
+	0x001F63B9, 0x0001AD4D, 0x00037657, 0x0004C260,
+	0x00068BE9, 0x000814F3, 0x0009A47C, 0x000B2D8A,
+	0x000CB694, 0x000E429D, 0x00128C26, 0x001455B0,
+	0x0015E4BA, 0x00176E4E, 0x0018F758, 0x001A8361,
+	0x001C0CEA, 0x001DD674, 0x001FA57D, 0x0001EE8B,
+	0x0003B795, 0x0005039E, 0x0006CD27, 0x000856B1,
+	0x0009E5C6, 0x000B6F4F, 0x000CF859, 0x000E8462,
+	0x00130DEB, 0x00149775, 0x00162603, 0x0017AF8C,
+	0x00193896, 0x001AC49F, 0x001C4E28, 0x001E17B2,
+	0x0000A6C7, 0x00023050, 0x0003F9DA, 0x00054563,
+	0x00070EEC, 0x00089876, 0x000A2704, 0x000BB08D,
+	0x000D3A17, 0x001185A0, 0x00134F29, 0x0014D8B3,
+	0x001667C8, 0x0017F151, 0x00197ADB, 0x001B0664,
+	0x001C8FED, 0x001E5977, 0x0000E805, 0x0002718F,
+	0x00043B18, 0x000586A1, 0x0007502B, 0x0008D9B4,
+	0x000A68C9, 0x000BF252, 0x000DBBDC, 0x0011C7E5,
+	0x001390EE, 0x00151A78, 0x0016A906, 0x00183290,
+	0x0019BC19, 0x001B4822, 0x001CD12C, 0x001E9AB5,
+	0x00000000, 0x00000000,
+};
+
+const u32 b43_ntab_tdtrn[] = {
+	0x061C061C, 0x0050EE68, 0xF592FE36, 0xFE5212F6,
+	0x00000C38, 0xFE5212F6, 0xF592FE36, 0x0050EE68,
+	0x061C061C, 0xEE680050, 0xFE36F592, 0x12F6FE52,
+	0x0C380000, 0x12F6FE52, 0xFE36F592, 0xEE680050,
+	0x061C061C, 0x0050EE68, 0xF592FE36, 0xFE5212F6,
+	0x00000C38, 0xFE5212F6, 0xF592FE36, 0x0050EE68,
+	0x061C061C, 0xEE680050, 0xFE36F592, 0x12F6FE52,
+	0x0C380000, 0x12F6FE52, 0xFE36F592, 0xEE680050,
+	0x05E305E3, 0x004DEF0C, 0xF5F3FE47, 0xFE611246,
+	0x00000BC7, 0xFE611246, 0xF5F3FE47, 0x004DEF0C,
+	0x05E305E3, 0xEF0C004D, 0xFE47F5F3, 0x1246FE61,
+	0x0BC70000, 0x1246FE61, 0xFE47F5F3, 0xEF0C004D,
+	0x05E305E3, 0x004DEF0C, 0xF5F3FE47, 0xFE611246,
+	0x00000BC7, 0xFE611246, 0xF5F3FE47, 0x004DEF0C,
+	0x05E305E3, 0xEF0C004D, 0xFE47F5F3, 0x1246FE61,
+	0x0BC70000, 0x1246FE61, 0xFE47F5F3, 0xEF0C004D,
+	0xFA58FA58, 0xF895043B, 0xFF4C09C0, 0xFBC6FFA8,
+	0xFB84F384, 0x0798F6F9, 0x05760122, 0x058409F6,
+	0x0B500000, 0x05B7F542, 0x08860432, 0x06DDFEE7,
+	0xFB84F384, 0xF9D90664, 0xF7E8025C, 0x00FFF7BD,
+	0x05A805A8, 0xF7BD00FF, 0x025CF7E8, 0x0664F9D9,
+	0xF384FB84, 0xFEE706DD, 0x04320886, 0xF54205B7,
+	0x00000B50, 0x09F60584, 0x01220576, 0xF6F90798,
+	0xF384FB84, 0xFFA8FBC6, 0x09C0FF4C, 0x043BF895,
+	0x02D402D4, 0x07DE0270, 0xFC96079C, 0xF90AFE94,
+	0xFE00FF2C, 0x02D4065D, 0x092A0096, 0x0014FBB8,
+	0xFD2CFD2C, 0x076AFB3C, 0x0096F752, 0xF991FD87,
+	0xFB2C0200, 0xFEB8F960, 0x08E0FC96, 0x049802A8,
+	0xFD2CFD2C, 0x02A80498, 0xFC9608E0, 0xF960FEB8,
+	0x0200FB2C, 0xFD87F991, 0xF7520096, 0xFB3C076A,
+	0xFD2CFD2C, 0xFBB80014, 0x0096092A, 0x065D02D4,
+	0xFF2CFE00, 0xFE94F90A, 0x079CFC96, 0x027007DE,
+	0x02D402D4, 0x027007DE, 0x079CFC96, 0xFE94F90A,
+	0xFF2CFE00, 0x065D02D4, 0x0096092A, 0xFBB80014,
+	0xFD2CFD2C, 0xFB3C076A, 0xF7520096, 0xFD87F991,
+	0x0200FB2C, 0xF960FEB8, 0xFC9608E0, 0x02A80498,
+	0xFD2CFD2C, 0x049802A8, 0x08E0FC96, 0xFEB8F960,
+	0xFB2C0200, 0xF991FD87, 0x0096F752, 0x076AFB3C,
+	0xFD2CFD2C, 0x0014FBB8, 0x092A0096, 0x02D4065D,
+	0xFE00FF2C, 0xF90AFE94, 0xFC96079C, 0x07DE0270,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x062A0000, 0xFEFA0759, 0x08B80908, 0xF396FC2D,
+	0xF9D6045C, 0xFC4EF608, 0xF748F596, 0x07B207BF,
+	0x062A062A, 0xF84EF841, 0xF748F596, 0x03B209F8,
+	0xF9D6045C, 0x0C6A03D3, 0x08B80908, 0x0106F8A7,
+	0x062A0000, 0xFEFAF8A7, 0x08B8F6F8, 0xF39603D3,
+	0xF9D6FBA4, 0xFC4E09F8, 0xF7480A6A, 0x07B2F841,
+	0x062AF9D6, 0xF84E07BF, 0xF7480A6A, 0x03B2F608,
+	0xF9D6FBA4, 0x0C6AFC2D, 0x08B8F6F8, 0x01060759,
+	0x062A0000, 0xFEFA0759, 0x08B80908, 0xF396FC2D,
+	0xF9D6045C, 0xFC4EF608, 0xF748F596, 0x07B207BF,
+	0x062A062A, 0xF84EF841, 0xF748F596, 0x03B209F8,
+	0xF9D6045C, 0x0C6A03D3, 0x08B80908, 0x0106F8A7,
+	0x062A0000, 0xFEFAF8A7, 0x08B8F6F8, 0xF39603D3,
+	0xF9D6FBA4, 0xFC4E09F8, 0xF7480A6A, 0x07B2F841,
+	0x062AF9D6, 0xF84E07BF, 0xF7480A6A, 0x03B2F608,
+	0xF9D6FBA4, 0x0C6AFC2D, 0x08B8F6F8, 0x01060759,
+	0x061C061C, 0xFF30009D, 0xFFB21141, 0xFD87FB54,
+	0xF65DFE59, 0x02EEF99E, 0x0166F03C, 0xFFF809B6,
+	0x000008A4, 0x000AF42B, 0x00EFF577, 0xFA840BF2,
+	0xFC02FF51, 0x08260F67, 0xFFF0036F, 0x0842F9C3,
+	0x00000000, 0x063DF7BE, 0xFC910010, 0xF099F7DA,
+	0x00AF03FE, 0xF40E057C, 0x0A89FF11, 0x0BD5FFF6,
+	0xF75C0000, 0xF64A0008, 0x0FC4FE9A, 0x0662FD12,
+	0x01A709A3, 0x04AC0279, 0xEEBF004E, 0xFF6300D0,
+	0xF9E4F9E4, 0x00D0FF63, 0x004EEEBF, 0x027904AC,
+	0x09A301A7, 0xFD120662, 0xFE9A0FC4, 0x0008F64A,
+	0x0000F75C, 0xFFF60BD5, 0xFF110A89, 0x057CF40E,
+	0x03FE00AF, 0xF7DAF099, 0x0010FC91, 0xF7BE063D,
+	0x00000000, 0xF9C30842, 0x036FFFF0, 0x0F670826,
+	0xFF51FC02, 0x0BF2FA84, 0xF57700EF, 0xF42B000A,
+	0x08A40000, 0x09B6FFF8, 0xF03C0166, 0xF99E02EE,
+	0xFE59F65D, 0xFB54FD87, 0x1141FFB2, 0x009DFF30,
+	0x05E30000, 0xFF060705, 0x085408A0, 0xF425FC59,
+	0xFA1D042A, 0xFC78F67A, 0xF7ACF60E, 0x075A0766,
+	0x05E305E3, 0xF8A6F89A, 0xF7ACF60E, 0x03880986,
+	0xFA1D042A, 0x0BDB03A7, 0x085408A0, 0x00FAF8FB,
+	0x05E30000, 0xFF06F8FB, 0x0854F760, 0xF42503A7,
+	0xFA1DFBD6, 0xFC780986, 0xF7AC09F2, 0x075AF89A,
+	0x05E3FA1D, 0xF8A60766, 0xF7AC09F2, 0x0388F67A,
+	0xFA1DFBD6, 0x0BDBFC59, 0x0854F760, 0x00FA0705,
+	0x05E30000, 0xFF060705, 0x085408A0, 0xF425FC59,
+	0xFA1D042A, 0xFC78F67A, 0xF7ACF60E, 0x075A0766,
+	0x05E305E3, 0xF8A6F89A, 0xF7ACF60E, 0x03880986,
+	0xFA1D042A, 0x0BDB03A7, 0x085408A0, 0x00FAF8FB,
+	0x05E30000, 0xFF06F8FB, 0x0854F760, 0xF42503A7,
+	0xFA1DFBD6, 0xFC780986, 0xF7AC09F2, 0x075AF89A,
+	0x05E3FA1D, 0xF8A60766, 0xF7AC09F2, 0x0388F67A,
+	0xFA1DFBD6, 0x0BDBFC59, 0x0854F760, 0x00FA0705,
+	0xFA58FA58, 0xF8F0FE00, 0x0448073D, 0xFDC9FE46,
+	0xF9910258, 0x089D0407, 0xFD5CF71A, 0x02AFFDE0,
+	0x083E0496, 0xFF5A0740, 0xFF7AFD97, 0x00FE01F1,
+	0x0009082E, 0xFA94FF75, 0xFECDF8EA, 0xFFB0F693,
+	0xFD2CFA58, 0x0433FF16, 0xFBA405DD, 0xFA610341,
+	0x06A606CB, 0x0039FD2D, 0x0677FA97, 0x01FA05E0,
+	0xF896003E, 0x075A068B, 0x012CFC3E, 0xFA23F98D,
+	0xFC7CFD43, 0xFF90FC0D, 0x01C10982, 0x00C601D6,
+	0xFD2CFD2C, 0x01D600C6, 0x098201C1, 0xFC0DFF90,
+	0xFD43FC7C, 0xF98DFA23, 0xFC3E012C, 0x068B075A,
+	0x003EF896, 0x05E001FA, 0xFA970677, 0xFD2D0039,
+	0x06CB06A6, 0x0341FA61, 0x05DDFBA4, 0xFF160433,
+	0xFA58FD2C, 0xF693FFB0, 0xF8EAFECD, 0xFF75FA94,
+	0x082E0009, 0x01F100FE, 0xFD97FF7A, 0x0740FF5A,
+	0x0496083E, 0xFDE002AF, 0xF71AFD5C, 0x0407089D,
+	0x0258F991, 0xFE46FDC9, 0x073D0448, 0xFE00F8F0,
+	0xFD2CFD2C, 0xFCE00500, 0xFC09FDDC, 0xFE680157,
+	0x04C70571, 0xFC3AFF21, 0xFCD70228, 0x056D0277,
+	0x0200FE00, 0x0022F927, 0xFE3C032B, 0xFC44FF3C,
+	0x03E9FBDB, 0x04570313, 0x04C9FF5C, 0x000D03B8,
+	0xFA580000, 0xFBE900D2, 0xF9D0FE0B, 0x0125FDF9,
+	0x042501BF, 0x0328FA2B, 0xFFA902F0, 0xFA250157,
+	0x0200FE00, 0x03740438, 0xFF0405FD, 0x030CFE52,
+	0x0037FB39, 0xFF6904C5, 0x04F8FD23, 0xFD31FC1B,
+	0xFD2CFD2C, 0xFC1BFD31, 0xFD2304F8, 0x04C5FF69,
+	0xFB390037, 0xFE52030C, 0x05FDFF04, 0x04380374,
+	0xFE000200, 0x0157FA25, 0x02F0FFA9, 0xFA2B0328,
+	0x01BF0425, 0xFDF90125, 0xFE0BF9D0, 0x00D2FBE9,
+	0x0000FA58, 0x03B8000D, 0xFF5C04C9, 0x03130457,
+	0xFBDB03E9, 0xFF3CFC44, 0x032BFE3C, 0xF9270022,
+	0xFE000200, 0x0277056D, 0x0228FCD7, 0xFF21FC3A,
+	0x057104C7, 0x0157FE68, 0xFDDCFC09, 0x0500FCE0,
+	0xFD2CFD2C, 0x0500FCE0, 0xFDDCFC09, 0x0157FE68,
+	0x057104C7, 0xFF21FC3A, 0x0228FCD7, 0x0277056D,
+	0xFE000200, 0xF9270022, 0x032BFE3C, 0xFF3CFC44,
+	0xFBDB03E9, 0x03130457, 0xFF5C04C9, 0x03B8000D,
+	0x0000FA58, 0x00D2FBE9, 0xFE0BF9D0, 0xFDF90125,
+	0x01BF0425, 0xFA2B0328, 0x02F0FFA9, 0x0157FA25,
+	0xFE000200, 0x04380374, 0x05FDFF04, 0xFE52030C,
+	0xFB390037, 0x04C5FF69, 0xFD2304F8, 0xFC1BFD31,
+	0xFD2CFD2C, 0xFD31FC1B, 0x04F8FD23, 0xFF6904C5,
+	0x0037FB39, 0x030CFE52, 0xFF0405FD, 0x03740438,
+	0x0200FE00, 0xFA250157, 0xFFA902F0, 0x0328FA2B,
+	0x042501BF, 0x0125FDF9, 0xF9D0FE0B, 0xFBE900D2,
+	0xFA580000, 0x000D03B8, 0x04C9FF5C, 0x04570313,
+	0x03E9FBDB, 0xFC44FF3C, 0xFE3C032B, 0x0022F927,
+	0x0200FE00, 0x056D0277, 0xFCD70228, 0xFC3AFF21,
+	0x04C70571, 0xFE680157, 0xFC09FDDC, 0xFCE00500,
+	0x05A80000, 0xFF1006BE, 0x0800084A, 0xF49CFC7E,
+	0xFA580400, 0xFC9CF6DA, 0xF800F672, 0x0710071C,
+	0x05A805A8, 0xF8F0F8E4, 0xF800F672, 0x03640926,
+	0xFA580400, 0x0B640382, 0x0800084A, 0x00F0F942,
+	0x05A80000, 0xFF10F942, 0x0800F7B6, 0xF49C0382,
+	0xFA58FC00, 0xFC9C0926, 0xF800098E, 0x0710F8E4,
+	0x05A8FA58, 0xF8F0071C, 0xF800098E, 0x0364F6DA,
+	0xFA58FC00, 0x0B64FC7E, 0x0800F7B6, 0x00F006BE,
+	0x05A80000, 0xFF1006BE, 0x0800084A, 0xF49CFC7E,
+	0xFA580400, 0xFC9CF6DA, 0xF800F672, 0x0710071C,
+	0x05A805A8, 0xF8F0F8E4, 0xF800F672, 0x03640926,
+	0xFA580400, 0x0B640382, 0x0800084A, 0x00F0F942,
+	0x05A80000, 0xFF10F942, 0x0800F7B6, 0xF49C0382,
+	0xFA58FC00, 0xFC9C0926, 0xF800098E, 0x0710F8E4,
+	0x05A8FA58, 0xF8F0071C, 0xF800098E, 0x0364F6DA,
+	0xFA58FC00, 0x0B64FC7E, 0x0800F7B6, 0x00F006BE,
+};
+
+const u32 b43_ntab_tmap[] = {
+	0x8A88AA80, 0x8AAAAA8A, 0x8A8A8AA8, 0x00000888,
+	0x88000000, 0x8A8A88AA, 0x8AA88888, 0x8888A8A8,
+	0xF1111110, 0x11111111, 0x11F11111, 0x00000111,
+	0x11000000, 0x1111F111, 0x11111111, 0x111111F1,
+	0x8A88AA80, 0x8AAAAA8A, 0x8A8A8AA8, 0x000AA888,
+	0x88880000, 0x8A8A88AA, 0x8AA88888, 0x8888A8A8,
+	0xA1111110, 0x11111111, 0x11C11111, 0x00000111,
+	0x11000000, 0x1111A111, 0x11111111, 0x111111A1,
+	0xA2222220, 0x22222222, 0x22C22222, 0x00000222,
+	0x22000000, 0x2222A222, 0x22222222, 0x222222A2,
+	0xF1111110, 0x11111111, 0x11F11111, 0x00011111,
+	0x11110000, 0x1111F111, 0x11111111, 0x111111F1,
+	0xA8AA88A0, 0xA88888A8, 0xA8A8A88A, 0x00088AAA,
+	0xAAAA0000, 0xA8A8AA88, 0xA88AAAAA, 0xAAAA8A8A,
+	0xAAA8AAA0, 0x8AAA8AAA, 0xAA8A8A8A, 0x000AAA88,
+	0x8AAA0000, 0xAAA8A888, 0x8AA88A8A, 0x8A88A888,
+	0x08080A00, 0x0A08080A, 0x080A0A08, 0x00080808,
+	0x080A0000, 0x080A0808, 0x080A0808, 0x0A0A0A08,
+	0xA0A0A0A0, 0x80A0A080, 0x8080A0A0, 0x00008080,
+	0x80A00000, 0x80A080A0, 0xA080A0A0, 0x8080A0A0,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x99999000, 0x9B9B99BB, 0x9BB99999, 0x9999B9B9,
+	0x9B99BB90, 0x9BBBBB9B, 0x9B9B9BB9, 0x00000999,
+	0x88000000, 0x8A8A88AA, 0x8AA88888, 0x8888A8A8,
+	0x8A88AA80, 0x8AAAAA8A, 0x8A8A8AA8, 0x00AAA888,
+	0x22000000, 0x2222B222, 0x22222222, 0x222222B2,
+	0xB2222220, 0x22222222, 0x22D22222, 0x00000222,
+	0x11000000, 0x1111A111, 0x11111111, 0x111111A1,
+	0xA1111110, 0x11111111, 0x11C11111, 0x00000111,
+	0x33000000, 0x3333B333, 0x33333333, 0x333333B3,
+	0xB3333330, 0x33333333, 0x33D33333, 0x00000333,
+	0x22000000, 0x2222A222, 0x22222222, 0x222222A2,
+	0xA2222220, 0x22222222, 0x22C22222, 0x00000222,
+	0x99B99B00, 0x9B9B99BB, 0x9BB99999, 0x9999B9B9,
+	0x9B99BB99, 0x9BBBBB9B, 0x9B9B9BB9, 0x00000999,
+	0x88000000, 0x8A8A88AA, 0x8AA88888, 0x8888A8A8,
+	0x8A88AA88, 0x8AAAAA8A, 0x8A8A8AA8, 0x08AAA888,
+	0x22222200, 0x2222F222, 0x22222222, 0x222222F2,
+	0x22222222, 0x22222222, 0x22F22222, 0x00000222,
+	0x11000000, 0x1111F111, 0x11111111, 0x11111111,
+	0xF1111111, 0x11111111, 0x11F11111, 0x01111111,
+	0xBB9BB900, 0xB9B9BB99, 0xB99BBBBB, 0xBBBB9B9B,
+	0xB9BB99BB, 0xB99999B9, 0xB9B9B99B, 0x00000BBB,
+	0xAA000000, 0xA8A8AA88, 0xA88AAAAA, 0xAAAA8A8A,
+	0xA8AA88AA, 0xA88888A8, 0xA8A8A88A, 0x0A888AAA,
+	0xAA000000, 0xA8A8AA88, 0xA88AAAAA, 0xAAAA8A8A,
+	0xA8AA88A0, 0xA88888A8, 0xA8A8A88A, 0x00000AAA,
+	0x88000000, 0x8A8A88AA, 0x8AA88888, 0x8888A8A8,
+	0x8A88AA80, 0x8AAAAA8A, 0x8A8A8AA8, 0x00000888,
+	0xBBBBBB00, 0x999BBBBB, 0x9BB99B9B, 0xB9B9B9BB,
+	0xB9B99BBB, 0xB9B9B9BB, 0xB9BB9B99, 0x00000999,
+	0x8A000000, 0xAA88A888, 0xA88888AA, 0xA88A8A88,
+	0xA88AA88A, 0x88A8AAAA, 0xA8AA8AAA, 0x0888A88A,
+	0x0B0B0B00, 0x090B0B0B, 0x0B090B0B, 0x0909090B,
+	0x09090B0B, 0x09090B0B, 0x09090B09, 0x00000909,
+	0x0A000000, 0x0A080808, 0x080A080A, 0x080A0A08,
+	0x080A080A, 0x0808080A, 0x0A0A0A08, 0x0808080A,
+	0xB0B0B000, 0x9090B0B0, 0x90B09090, 0xB0B0B090,
+	0xB0B090B0, 0x90B0B0B0, 0xB0B09090, 0x00000090,
+	0x80000000, 0xA080A080, 0xA08080A0, 0xA0808080,
+	0xA080A080, 0x80A0A0A0, 0xA0A080A0, 0x00A0A0A0,
+	0x22000000, 0x2222F222, 0x22222222, 0x222222F2,
+	0xF2222220, 0x22222222, 0x22F22222, 0x00000222,
+	0x11000000, 0x1111F111, 0x11111111, 0x111111F1,
+	0xF1111110, 0x11111111, 0x11F11111, 0x00000111,
+	0x33000000, 0x3333F333, 0x33333333, 0x333333F3,
+	0xF3333330, 0x33333333, 0x33F33333, 0x00000333,
+	0x22000000, 0x2222F222, 0x22222222, 0x222222F2,
+	0xF2222220, 0x22222222, 0x22F22222, 0x00000222,
+	0x99000000, 0x9B9B99BB, 0x9BB99999, 0x9999B9B9,
+	0x9B99BB90, 0x9BBBBB9B, 0x9B9B9BB9, 0x00000999,
+	0x88000000, 0x8A8A88AA, 0x8AA88888, 0x8888A8A8,
+	0x8A88AA80, 0x8AAAAA8A, 0x8A8A8AA8, 0x00000888,
+	0x88888000, 0x8A8A88AA, 0x8AA88888, 0x8888A8A8,
+	0x8A88AA80, 0x8AAAAA8A, 0x8A8A8AA8, 0x00000888,
+	0x88000000, 0x8A8A88AA, 0x8AA88888, 0x8888A8A8,
+	0x8A88AA80, 0x8AAAAA8A, 0x8A8A8AA8, 0x00AAA888,
+	0x88A88A00, 0x8A8A88AA, 0x8AA88888, 0x8888A8A8,
+	0x8A88AA88, 0x8AAAAA8A, 0x8A8A8AA8, 0x00000888,
+	0x88000000, 0x8A8A88AA, 0x8AA88888, 0x8888A8A8,
+	0x8A88AA88, 0x8AAAAA8A, 0x8A8A8AA8, 0x08AAA888,
+	0x11000000, 0x1111A111, 0x11111111, 0x111111A1,
+	0xA1111110, 0x11111111, 0x11C11111, 0x00000111,
+	0x11000000, 0x1111A111, 0x11111111, 0x111111A1,
+	0xA1111110, 0x11111111, 0x11C11111, 0x00000111,
+	0x88000000, 0x8A8A88AA, 0x8AA88888, 0x8888A8A8,
+	0x8A88AA80, 0x8AAAAA8A, 0x8A8A8AA8, 0x00000888,
+	0x88000000, 0x8A8A88AA, 0x8AA88888, 0x8888A8A8,
+	0x8A88AA80, 0x8AAAAA8A, 0x8A8A8AA8, 0x00000888,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+};
+
+static inline void assert_ntab_array_sizes(void)
+{
+#undef check
+#define check(table, size)	\
+	BUILD_BUG_ON(ARRAY_SIZE(b43_ntab_##table) != B43_NTAB_##size##_SIZE)
+
+	check(adjustpower0, C0_ADJPLT);
+	check(adjustpower1, C1_ADJPLT);
+	check(bdi, BDI);
+	check(channelest, CHANEST);
+	check(estimatepowerlt0, C0_ESTPLT);
+	check(estimatepowerlt1, C1_ESTPLT);
+	check(framelookup, FRAMELT);
+	check(framestruct, FRAMESTRUCT);
+	check(gainctl0, C0_GAINCTL);
+	check(gainctl1, C1_GAINCTL);
+	check(intlevel, INTLEVEL);
+	check(iqlt0, C0_IQLT);
+	check(iqlt1, C1_IQLT);
+	check(loftlt0, C0_LOFEEDTH);
+	check(loftlt1, C1_LOFEEDTH);
+	check(mcs, MCS);
+	check(noisevar10, NOISEVAR10);
+	check(noisevar11, NOISEVAR11);
+	check(pilot, PILOT);
+	check(pilotlt, PILOTLT);
+	check(tdi20a0, TDI20A0);
+	check(tdi20a1, TDI20A1);
+	check(tdi40a0, TDI40A0);
+	check(tdi40a1, TDI40A1);
+	check(tdtrn, TDTRN);
+	check(tmap, TMAP);
+
+#undef check
+}
+
+void b43_ntab_write(struct b43_wldev *dev, u32 offset, u32 value)
+{
+	u32 type;
+
+	type = offset & B43_NTAB_TYPEMASK;
+	offset &= 0xFFFF;
+
+	switch (type) {
+	case B43_NTAB_8BIT:
+		B43_WARN_ON(value & ~0xFF);
+		b43_phy_write(dev, B43_NPHY_TABLE_ADDR, offset);
+		b43_phy_write(dev, B43_NPHY_TABLE_DATALO, value);
+		break;
+	case B43_NTAB_16BIT:
+		B43_WARN_ON(value & ~0xFFFF);
+		b43_phy_write(dev, B43_NPHY_TABLE_ADDR, offset);
+		b43_phy_write(dev, B43_NPHY_TABLE_DATALO, value);
+		break;
+	case B43_NTAB_32BIT:
+		b43_phy_write(dev, B43_NPHY_TABLE_ADDR, offset);
+		b43_phy_write(dev, B43_NPHY_TABLE_DATAHI, value >> 16);
+		b43_phy_write(dev, B43_NPHY_TABLE_DATALO, value & 0xFFFF);
+		break;
+	default:
+		B43_WARN_ON(1);
+	}
+
+	return;
+
+	/* Some compiletime assertions... */
+	assert_ntab_array_sizes();
+}
diff --git a/package/b43/src/tables_nphy.h b/package/b43/src/tables_nphy.h
new file mode 100644
index 0000000000..4d498b053e
--- /dev/null
+++ b/package/b43/src/tables_nphy.h
@@ -0,0 +1,159 @@
+#ifndef B43_TABLES_NPHY_H_
+#define B43_TABLES_NPHY_H_
+
+#include <linux/types.h>
+
+
+struct b43_nphy_channeltab_entry {
+	/* The channel number */
+	u8 channel;
+	/* Radio register values on channelswitch */
+	u8 radio_pll_ref;
+	u8 radio_rf_pllmod0;
+	u8 radio_rf_pllmod1;
+	u8 radio_vco_captail;
+	u8 radio_vco_cal1;
+	u8 radio_vco_cal2;
+	u8 radio_pll_lfc1;
+	u8 radio_pll_lfr1;
+	u8 radio_pll_lfc2;
+	u8 radio_lgbuf_cenbuf;
+	u8 radio_lgen_tune1;
+	u8 radio_lgen_tune2;
+	u8 radio_c1_lgbuf_atune;
+	u8 radio_c1_lgbuf_gtune;
+	u8 radio_c1_rx_rfr1;
+	u8 radio_c1_tx_pgapadtn;
+	u8 radio_c1_tx_mxbgtrim;
+	u8 radio_c2_lgbuf_atune;
+	u8 radio_c2_lgbuf_gtune;
+	u8 radio_c2_rx_rfr1;
+	u8 radio_c2_tx_pgapadtn;
+	u8 radio_c2_tx_mxbgtrim;
+	/* PHY register values on channelswitch */
+	u16 phy_bw1a;
+	u16 phy_bw2;
+	u16 phy_bw3;
+	u16 phy_bw4;
+	u16 phy_bw5;
+	u16 phy_bw6;
+	/* The channel frequency in MHz */
+	u16 freq;
+	/* An unknown value */
+	u16 unk2;
+};
+
+
+struct b43_wldev;
+
+/* Upload the default register value table.
+ * If "ghz5" is true, we upload the 5Ghz table. Otherwise the 2.4Ghz
+ * table is uploaded. If "ignore_uploadflag" is true, we upload any value
+ * and ignore the "UPLOAD" flag. */
+void b2055_upload_inittab(struct b43_wldev *dev,
+			  bool ghz5, bool ignore_uploadflag);
+
+
+/* Get the NPHY Channel Switch Table entry for a channel number.
+ * Returns NULL on failure to find an entry. */
+const struct b43_nphy_channeltab_entry *
+b43_nphy_get_chantabent(struct b43_wldev *dev, u8 channel);
+
+
+/* The N-PHY tables. */
+
+#define B43_NTAB_TYPEMASK		0xF0000000
+#define B43_NTAB_8BIT			0x10000000
+#define B43_NTAB_16BIT			0x20000000
+#define B43_NTAB_32BIT			0x30000000
+#define B43_NTAB8(table, offset)	(((table) << 10) | (offset) | B43_NTAB_8BIT)
+#define B43_NTAB16(table, offset)	(((table) << 10) | (offset) | B43_NTAB_16BIT)
+#define B43_NTAB32(table, offset)	(((table) << 10) | (offset) | B43_NTAB_32BIT)
+
+/* Static N-PHY tables */
+#define B43_NTAB_FRAMESTRUCT		B43_NTAB32(0x0A, 0x000) /* Frame Struct Table */
+#define B43_NTAB_FRAMESTRUCT_SIZE	832
+#define B43_NTAB_FRAMELT		B43_NTAB8 (0x18, 0x000) /* Frame Lookup Table */
+#define B43_NTAB_FRAMELT_SIZE		32
+#define B43_NTAB_TMAP			B43_NTAB32(0x0C, 0x000) /* T Map Table */
+#define B43_NTAB_TMAP_SIZE		448
+#define B43_NTAB_TDTRN			B43_NTAB32(0x0E, 0x000) /* TDTRN Table */
+#define B43_NTAB_TDTRN_SIZE		704
+#define B43_NTAB_INTLEVEL		B43_NTAB32(0x0D, 0x000) /* Int Level Table */
+#define B43_NTAB_INTLEVEL_SIZE		7
+#define B43_NTAB_PILOT			B43_NTAB16(0x0B, 0x000) /* Pilot Table */
+#define B43_NTAB_PILOT_SIZE		88
+#define B43_NTAB_PILOTLT		B43_NTAB32(0x14, 0x000) /* Pilot Lookup Table */
+#define B43_NTAB_PILOTLT_SIZE		6
+#define B43_NTAB_TDI20A0		B43_NTAB32(0x13, 0x080) /* TDI Table 20 Antenna 0 */
+#define B43_NTAB_TDI20A0_SIZE		55
+#define B43_NTAB_TDI20A1		B43_NTAB32(0x13, 0x100) /* TDI Table 20 Antenna 1 */
+#define B43_NTAB_TDI20A1_SIZE		55
+#define B43_NTAB_TDI40A0		B43_NTAB32(0x13, 0x280) /* TDI Table 40 Antenna 0 */
+#define B43_NTAB_TDI40A0_SIZE		110
+#define B43_NTAB_TDI40A1		B43_NTAB32(0x13, 0x300) /* TDI Table 40 Antenna 1 */
+#define B43_NTAB_TDI40A1_SIZE		110
+#define B43_NTAB_BDI			B43_NTAB16(0x15, 0x000) /* BDI Table */
+#define B43_NTAB_BDI_SIZE		6
+#define B43_NTAB_CHANEST		B43_NTAB32(0x16, 0x000) /* Channel Estimate Table */
+#define B43_NTAB_CHANEST_SIZE		96
+#define B43_NTAB_MCS			B43_NTAB8 (0x12, 0x000) /* MCS Table */
+#define B43_NTAB_MCS_SIZE		128
+
+/* Volatile N-PHY tables */
+#define B43_NTAB_NOISEVAR10		B43_NTAB32(0x10, 0x000) /* Noise Var Table 10 */
+#define B43_NTAB_NOISEVAR10_SIZE	256
+#define B43_NTAB_NOISEVAR11		B43_NTAB32(0x10, 0x080) /* Noise Var Table 11 */
+#define B43_NTAB_NOISEVAR11_SIZE	256
+#define B43_NTAB_C0_ESTPLT		B43_NTAB8 (0x1A, 0x000) /* Estimate Power Lookup Table Core 0 */
+#define B43_NTAB_C0_ESTPLT_SIZE		64
+#define B43_NTAB_C1_ESTPLT		B43_NTAB8 (0x1B, 0x000) /* Estimate Power Lookup Table Core 1 */
+#define B43_NTAB_C1_ESTPLT_SIZE		64
+#define B43_NTAB_C0_ADJPLT		B43_NTAB8 (0x1A, 0x040) /* Adjust Power Lookup Table Core 0 */
+#define B43_NTAB_C0_ADJPLT_SIZE		128
+#define B43_NTAB_C1_ADJPLT		B43_NTAB8 (0x1B, 0x040) /* Adjust Power Lookup Table Core 1 */
+#define B43_NTAB_C1_ADJPLT_SIZE		128
+#define B43_NTAB_C0_GAINCTL		B43_NTAB32(0x1A, 0x0C0) /* Gain Control Lookup Table Core 0 */
+#define B43_NTAB_C0_GAINCTL_SIZE	128
+#define B43_NTAB_C1_GAINCTL		B43_NTAB32(0x1B, 0x0C0) /* Gain Control Lookup Table Core 1 */
+#define B43_NTAB_C1_GAINCTL_SIZE	128
+#define B43_NTAB_C0_IQLT		B43_NTAB32(0x1A, 0x140) /* IQ Lookup Table Core 0 */
+#define B43_NTAB_C0_IQLT_SIZE		128
+#define B43_NTAB_C1_IQLT		B43_NTAB32(0x1B, 0x140) /* IQ Lookup Table Core 1 */
+#define B43_NTAB_C1_IQLT_SIZE		128
+#define B43_NTAB_C0_LOFEEDTH		B43_NTAB16(0x1A, 0x1C0) /* Local Oscillator Feed Through Lookup Table Core 0 */
+#define B43_NTAB_C0_LOFEEDTH_SIZE	128
+#define B43_NTAB_C1_LOFEEDTH		B43_NTAB16(0x1B, 0x1C0) /* Local Oscillator Feed Through Lookup Table Core 1 */
+#define B43_NTAB_C1_LOFEEDTH_SIZE	128
+
+void b43_ntab_write(struct b43_wldev *dev, u32 offset, u32 value);
+
+extern const u8 b43_ntab_adjustpower0[];
+extern const u8 b43_ntab_adjustpower1[];
+extern const u16 b43_ntab_bdi[];
+extern const u32 b43_ntab_channelest[];
+extern const u8 b43_ntab_estimatepowerlt0[];
+extern const u8 b43_ntab_estimatepowerlt1[];
+extern const u8 b43_ntab_framelookup[];
+extern const u32 b43_ntab_framestruct[];
+extern const u32 b43_ntab_gainctl0[];
+extern const u32 b43_ntab_gainctl1[];
+extern const u32 b43_ntab_intlevel[];
+extern const u32 b43_ntab_iqlt0[];
+extern const u32 b43_ntab_iqlt1[];
+extern const u16 b43_ntab_loftlt0[];
+extern const u16 b43_ntab_loftlt1[];
+extern const u8 b43_ntab_mcs[];
+extern const u32 b43_ntab_noisevar10[];
+extern const u32 b43_ntab_noisevar11[];
+extern const u16 b43_ntab_pilot[];
+extern const u32 b43_ntab_pilotlt[];
+extern const u32 b43_ntab_tdi20a0[];
+extern const u32 b43_ntab_tdi20a1[];
+extern const u32 b43_ntab_tdi40a0[];
+extern const u32 b43_ntab_tdi40a1[];
+extern const u32 b43_ntab_tdtrn[];
+extern const u32 b43_ntab_tmap[];
+
+
+#endif /* B43_TABLES_NPHY_H_ */
diff --git a/package/b43/src/wa.c b/package/b43/src/wa.c
new file mode 100644
index 0000000000..e632125cb7
--- /dev/null
+++ b/package/b43/src/wa.c
@@ -0,0 +1,674 @@
+/*
+
+  Broadcom B43 wireless driver
+
+  PHY workarounds.
+
+  Copyright (c) 2005-2007 Stefano Brivio <stefano.brivio@polimi.it>
+  Copyright (c) 2005-2007 Michael Buesch <mbuesch@freenet.de>
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 of the License, or
+  (at your option) any later version.
+
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program; see the file COPYING.  If not, write to
+  the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
+  Boston, MA 02110-1301, USA.
+
+*/
+
+#include "b43.h"
+#include "main.h"
+#include "tables.h"
+#include "phy.h"
+#include "wa.h"
+
+static void b43_wa_papd(struct b43_wldev *dev)
+{
+	u16 backup;
+
+	backup = b43_ofdmtab_read16(dev, B43_OFDMTAB_PWRDYN2, 0);
+	b43_ofdmtab_write16(dev, B43_OFDMTAB_PWRDYN2, 0, 7);
+	b43_ofdmtab_write16(dev, B43_OFDMTAB_UNKNOWN_APHY, 0, 0);
+	b43_dummy_transmission(dev);
+	b43_ofdmtab_write16(dev, B43_OFDMTAB_PWRDYN2, 0, backup);
+}
+
+static void b43_wa_auxclipthr(struct b43_wldev *dev)
+{
+	b43_phy_write(dev, B43_PHY_OFDM(0x8E), 0x3800);
+}
+
+static void b43_wa_afcdac(struct b43_wldev *dev)
+{
+	b43_phy_write(dev, 0x0035, 0x03FF);
+	b43_phy_write(dev, 0x0036, 0x0400);
+}
+
+static void b43_wa_txdc_offset(struct b43_wldev *dev)
+{
+	b43_ofdmtab_write16(dev, B43_OFDMTAB_DC, 0, 0x0051);
+}
+
+void b43_wa_initgains(struct b43_wldev *dev)
+{
+	struct b43_phy *phy = &dev->phy;
+
+	b43_phy_write(dev, B43_PHY_LNAHPFCTL, 0x1FF9);
+	b43_phy_write(dev, B43_PHY_LPFGAINCTL,
+		b43_phy_read(dev, B43_PHY_LPFGAINCTL) & 0xFF0F);
+	if (phy->rev <= 2)
+		b43_ofdmtab_write16(dev, B43_OFDMTAB_LPFGAIN, 0, 0x1FBF);
+	b43_radio_write16(dev, 0x0002, 0x1FBF);
+
+	b43_phy_write(dev, 0x0024, 0x4680);
+	b43_phy_write(dev, 0x0020, 0x0003);
+	b43_phy_write(dev, 0x001D, 0x0F40);
+	b43_phy_write(dev, 0x001F, 0x1C00);
+	if (phy->rev <= 3)
+		b43_phy_write(dev, 0x002A,
+			(b43_phy_read(dev, 0x002A) & 0x00FF) | 0x0400);
+	else if (phy->rev == 5) {
+		b43_phy_write(dev, 0x002A,
+			(b43_phy_read(dev, 0x002A) & 0x00FF) | 0x1A00);
+		b43_phy_write(dev, 0x00CC, 0x2121);
+	}
+	if (phy->rev >= 3)
+		b43_phy_write(dev, 0x00BA, 0x3ED5);
+}
+
+static void b43_wa_divider(struct b43_wldev *dev)
+{
+	b43_phy_write(dev, 0x002B, b43_phy_read(dev, 0x002B) & ~0x0100);
+	b43_phy_write(dev, 0x008E, 0x58C1);
+}
+
+static void b43_wa_gt(struct b43_wldev *dev) /* Gain table. */
+{
+	if (dev->phy.rev <= 2) {
+		b43_ofdmtab_write16(dev, B43_OFDMTAB_GAIN2, 0, 15);
+		b43_ofdmtab_write16(dev, B43_OFDMTAB_GAIN2, 1, 31);
+		b43_ofdmtab_write16(dev, B43_OFDMTAB_GAIN2, 2, 42);
+		b43_ofdmtab_write16(dev, B43_OFDMTAB_GAIN2, 3, 48);
+		b43_ofdmtab_write16(dev, B43_OFDMTAB_GAIN2, 4, 58);
+		b43_ofdmtab_write16(dev, B43_OFDMTAB_GAIN0, 0, 19);
+		b43_ofdmtab_write16(dev, B43_OFDMTAB_GAIN0, 1, 19);
+		b43_ofdmtab_write16(dev, B43_OFDMTAB_GAIN0, 2, 19);
+		b43_ofdmtab_write16(dev, B43_OFDMTAB_GAIN0, 3, 19);
+		b43_ofdmtab_write16(dev, B43_OFDMTAB_GAIN0, 4, 21);
+		b43_ofdmtab_write16(dev, B43_OFDMTAB_GAIN0, 5, 21);
+		b43_ofdmtab_write16(dev, B43_OFDMTAB_GAIN0, 6, 25);
+		b43_ofdmtab_write16(dev, B43_OFDMTAB_GAIN1, 0, 3);
+		b43_ofdmtab_write16(dev, B43_OFDMTAB_GAIN1, 1, 3);
+		b43_ofdmtab_write16(dev, B43_OFDMTAB_GAIN1, 2, 7);
+	} else {
+		b43_ofdmtab_write16(dev, B43_OFDMTAB_GAIN0, 0, 19);
+		b43_ofdmtab_write16(dev, B43_OFDMTAB_GAIN0, 1, 19);
+		b43_ofdmtab_write16(dev, B43_OFDMTAB_GAIN0, 2, 19);
+		b43_ofdmtab_write16(dev, B43_OFDMTAB_GAIN0, 3, 19);
+		b43_ofdmtab_write16(dev, B43_OFDMTAB_GAIN0, 4, 21);
+		b43_ofdmtab_write16(dev, B43_OFDMTAB_GAIN0, 5, 21);
+		b43_ofdmtab_write16(dev, B43_OFDMTAB_GAIN0, 6, 25);
+	}
+}
+
+static void b43_wa_rssi_lt(struct b43_wldev *dev) /* RSSI lookup table */
+{
+	int i;
+
+	if (0 /* FIXME: For APHY.rev=2 this might be needed */) {
+		for (i = 0; i < 8; i++)
+			b43_ofdmtab_write16(dev, B43_OFDMTAB_RSSI, i, i + 8);
+		for (i = 8; i < 16; i++)
+			b43_ofdmtab_write16(dev, B43_OFDMTAB_RSSI, i, i - 8);
+	} else {
+		for (i = 0; i < 64; i++)
+			b43_ofdmtab_write16(dev, B43_OFDMTAB_RSSI, i, i);
+	}
+}
+
+static void b43_wa_analog(struct b43_wldev *dev)
+{
+	struct b43_phy *phy = &dev->phy;
+	u16 ofdmrev;
+
+	ofdmrev = b43_phy_read(dev, B43_PHY_VERSION_OFDM) & B43_PHYVER_VERSION;
+	if (ofdmrev > 2) {
+		if (phy->type == B43_PHYTYPE_A)
+			b43_phy_write(dev, B43_PHY_PWRDOWN, 0x1808);
+		else
+			b43_phy_write(dev, B43_PHY_PWRDOWN, 0x1000);
+	} else {
+		b43_ofdmtab_write16(dev, B43_OFDMTAB_DAC, 3, 0x1044);
+		b43_ofdmtab_write16(dev, B43_OFDMTAB_DAC, 4, 0x7201);
+		b43_ofdmtab_write16(dev, B43_OFDMTAB_DAC, 6, 0x0040);
+	}
+}
+
+static void b43_wa_dac(struct b43_wldev *dev)
+{
+	if (dev->phy.analog == 1)
+		b43_ofdmtab_write16(dev, B43_OFDMTAB_DAC, 1,
+			(b43_ofdmtab_read16(dev, B43_OFDMTAB_DAC, 1) & ~0x0034) | 0x0008);
+	else
+		b43_ofdmtab_write16(dev, B43_OFDMTAB_DAC, 1,
+			(b43_ofdmtab_read16(dev, B43_OFDMTAB_DAC, 1) & ~0x0078) | 0x0010);
+}
+
+static void b43_wa_fft(struct b43_wldev *dev) /* Fine frequency table */
+{
+	int i;
+
+	if (dev->phy.type == B43_PHYTYPE_A)
+		for (i = 0; i < B43_TAB_FINEFREQA_SIZE; i++)
+			b43_ofdmtab_write16(dev, B43_OFDMTAB_DACRFPABB, i, b43_tab_finefreqa[i]);
+	else
+		for (i = 0; i < B43_TAB_FINEFREQG_SIZE; i++)
+			b43_ofdmtab_write16(dev, B43_OFDMTAB_DACRFPABB, i, b43_tab_finefreqg[i]);
+}
+
+static void b43_wa_nft(struct b43_wldev *dev) /* Noise figure table */
+{
+	struct b43_phy *phy = &dev->phy;
+	int i;
+
+	if (phy->type == B43_PHYTYPE_A) {
+		if (phy->rev == 2)
+			for (i = 0; i < B43_TAB_NOISEA2_SIZE; i++)
+				b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC2, i, b43_tab_noisea2[i]);
+		else
+			for (i = 0; i < B43_TAB_NOISEA3_SIZE; i++)
+				b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC2, i, b43_tab_noisea3[i]);
+	} else {
+		if (phy->rev == 1)
+			for (i = 0; i < B43_TAB_NOISEG1_SIZE; i++)
+				b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC2, i, b43_tab_noiseg1[i]);
+		else
+			for (i = 0; i < B43_TAB_NOISEG2_SIZE; i++)
+				b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC2, i, b43_tab_noiseg2[i]);
+	}
+}
+
+static void b43_wa_rt(struct b43_wldev *dev) /* Rotor table */
+{
+	int i;
+
+	for (i = 0; i < B43_TAB_ROTOR_SIZE; i++)
+		b43_ofdmtab_write32(dev, B43_OFDMTAB_ROTOR, i, b43_tab_rotor[i]);
+}
+
+static void b43_wa_nst(struct b43_wldev *dev) /* Noise scale table */
+{
+	struct b43_phy *phy = &dev->phy;
+	int i;
+
+	if (phy->type == B43_PHYTYPE_A) {
+		if (phy->rev <= 1)
+			for (i = 0; i < B43_TAB_NOISESCALE_SIZE; i++)
+				b43_ofdmtab_write16(dev, B43_OFDMTAB_NOISESCALE,
+							i, 0);
+		else if (phy->rev == 2)
+			for (i = 0; i < B43_TAB_NOISESCALE_SIZE; i++)
+				b43_ofdmtab_write16(dev, B43_OFDMTAB_NOISESCALE,
+							i, b43_tab_noisescalea2[i]);
+		else if (phy->rev == 3)
+			for (i = 0; i < B43_TAB_NOISESCALE_SIZE; i++)
+				b43_ofdmtab_write16(dev, B43_OFDMTAB_NOISESCALE,
+							i, b43_tab_noisescalea3[i]);
+		else
+			for (i = 0; i < B43_TAB_NOISESCALE_SIZE; i++)
+				b43_ofdmtab_write16(dev, B43_OFDMTAB_NOISESCALE,
+							i, b43_tab_noisescaleg3[i]);
+	} else {
+		if (phy->rev >= 6) {
+			if (b43_phy_read(dev, B43_PHY_ENCORE) & B43_PHY_ENCORE_EN)
+				for (i = 0; i < B43_TAB_NOISESCALE_SIZE; i++)
+					b43_ofdmtab_write16(dev, B43_OFDMTAB_NOISESCALE,
+						i, b43_tab_noisescaleg3[i]);
+			else
+				for (i = 0; i < B43_TAB_NOISESCALE_SIZE; i++)
+					b43_ofdmtab_write16(dev, B43_OFDMTAB_NOISESCALE,
+						i, b43_tab_noisescaleg2[i]);
+		} else {
+			for (i = 0; i < B43_TAB_NOISESCALE_SIZE; i++)
+				b43_ofdmtab_write16(dev, B43_OFDMTAB_NOISESCALE,
+							i, b43_tab_noisescaleg1[i]);
+		}
+	}
+}
+
+static void b43_wa_art(struct b43_wldev *dev) /* ADV retard table */
+{
+	int i;
+
+	for (i = 0; i < B43_TAB_RETARD_SIZE; i++)
+			b43_ofdmtab_write32(dev, B43_OFDMTAB_ADVRETARD,
+				i, b43_tab_retard[i]);
+}
+
+static void b43_wa_txlna_gain(struct b43_wldev *dev)
+{
+	b43_ofdmtab_write16(dev, B43_OFDMTAB_DC, 13, 0x0000);
+}
+
+static void b43_wa_crs_reset(struct b43_wldev *dev)
+{
+	b43_phy_write(dev, 0x002C, 0x0064);
+}
+
+static void b43_wa_2060txlna_gain(struct b43_wldev *dev)
+{
+	b43_hf_write(dev, b43_hf_read(dev) |
+			 B43_HF_2060W);
+}
+
+static void b43_wa_lms(struct b43_wldev *dev)
+{
+	b43_phy_write(dev, 0x0055,
+		(b43_phy_read(dev, 0x0055) & 0xFFC0) | 0x0004);
+}
+
+static void b43_wa_mixedsignal(struct b43_wldev *dev)
+{
+	b43_ofdmtab_write16(dev, B43_OFDMTAB_DAC, 1, 3);
+}
+
+static void b43_wa_msst(struct b43_wldev *dev) /* Min sigma square table */
+{
+	struct b43_phy *phy = &dev->phy;
+	int i;
+	const u16 *tab;
+
+	if (phy->type == B43_PHYTYPE_A) {
+		tab = b43_tab_sigmasqr1;
+	} else if (phy->type == B43_PHYTYPE_G) {
+		tab = b43_tab_sigmasqr2;
+	} else {
+		B43_WARN_ON(1);
+		return;
+	}
+
+	for (i = 0; i < B43_TAB_SIGMASQR_SIZE; i++) {
+		b43_ofdmtab_write16(dev, B43_OFDMTAB_MINSIGSQ,
+					i, tab[i]);
+	}
+}
+
+static void b43_wa_iqadc(struct b43_wldev *dev)
+{
+	if (dev->phy.analog == 4)
+		b43_ofdmtab_write16(dev, B43_OFDMTAB_DAC, 0,
+			b43_ofdmtab_read16(dev, B43_OFDMTAB_DAC, 0) & ~0xF000);
+}
+
+static void b43_wa_crs_ed(struct b43_wldev *dev)
+{
+	struct b43_phy *phy = &dev->phy;
+
+	if (phy->rev == 1) {
+		b43_phy_write(dev, B43_PHY_CRSTHRES1_R1, 0x4F19);
+	} else if (phy->rev == 2) {
+		b43_phy_write(dev, B43_PHY_CRSTHRES1, 0x1861);
+		b43_phy_write(dev, B43_PHY_CRSTHRES2, 0x0271);
+		b43_phy_write(dev, B43_PHY_ANTDWELL,
+				  b43_phy_read(dev, B43_PHY_ANTDWELL)
+				  | 0x0800);
+	} else {
+		b43_phy_write(dev, B43_PHY_CRSTHRES1, 0x0098);
+		b43_phy_write(dev, B43_PHY_CRSTHRES2, 0x0070);
+		b43_phy_write(dev, B43_PHY_OFDM(0xC9), 0x0080);
+		b43_phy_write(dev, B43_PHY_ANTDWELL,
+				  b43_phy_read(dev, B43_PHY_ANTDWELL)
+				  | 0x0800);
+	}
+}
+
+static void b43_wa_crs_thr(struct b43_wldev *dev)
+{
+	b43_phy_write(dev, B43_PHY_CRS0,
+			(b43_phy_read(dev, B43_PHY_CRS0) & ~0x03C0) | 0xD000);
+}
+
+static void b43_wa_crs_blank(struct b43_wldev *dev)
+{
+	b43_phy_write(dev, B43_PHY_OFDM(0x2C), 0x005A);
+}
+
+static void b43_wa_cck_shiftbits(struct b43_wldev *dev)
+{
+	b43_phy_write(dev, B43_PHY_CCKSHIFTBITS, 0x0026);
+}
+
+static void b43_wa_wrssi_offset(struct b43_wldev *dev)
+{
+	int i;
+
+	if (dev->phy.rev == 1) {
+		for (i = 0; i < 16; i++) {
+			b43_ofdmtab_write16(dev, B43_OFDMTAB_WRSSI_R1,
+						i, 0x0020);
+		}
+	} else {
+		for (i = 0; i < 32; i++) {
+			b43_ofdmtab_write16(dev, B43_OFDMTAB_WRSSI,
+						i, 0x0820);
+		}
+	}
+}
+
+static void b43_wa_txpuoff_rxpuon(struct b43_wldev *dev)
+{
+	b43_ofdmtab_write16(dev, B43_OFDMTAB_UNKNOWN_0F, 2, 15);
+	b43_ofdmtab_write16(dev, B43_OFDMTAB_UNKNOWN_0F, 3, 20);
+}
+
+static void b43_wa_altagc(struct b43_wldev *dev)
+{
+	struct b43_phy *phy = &dev->phy;
+
+	if (phy->rev == 1) {
+		b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC1_R1, 0, 254);
+		b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC1_R1, 1, 13);
+		b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC1_R1, 2, 19);
+		b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC1_R1, 3, 25);
+		b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC2, 0, 0x2710);
+		b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC2, 1, 0x9B83);
+		b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC2, 2, 0x9B83);
+		b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC2, 3, 0x0F8D);
+		b43_phy_write(dev, B43_PHY_LMS, 4);
+	} else {
+		b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC1, 0, 254);
+		b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC1, 1, 13);
+		b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC1, 2, 19);
+		b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC1, 3, 25);
+	}
+
+	b43_phy_write(dev, B43_PHY_CCKSHIFTBITS_WA,
+		(b43_phy_read(dev, B43_PHY_CCKSHIFTBITS_WA) & ~0xFF00) | 0x5700);
+	b43_phy_write(dev, B43_PHY_OFDM(0x1A),
+		(b43_phy_read(dev, B43_PHY_OFDM(0x1A)) & ~0x007F) | 0x000F);
+	b43_phy_write(dev, B43_PHY_OFDM(0x1A),
+		(b43_phy_read(dev, B43_PHY_OFDM(0x1A)) & ~0x3F80) | 0x2B80);
+	b43_phy_write(dev, B43_PHY_ANTWRSETT,
+		(b43_phy_read(dev, B43_PHY_ANTWRSETT) & 0xF0FF) | 0x0300);
+	b43_radio_write16(dev, 0x7A,
+		b43_radio_read16(dev, 0x7A) | 0x0008);
+	b43_phy_write(dev, B43_PHY_N1P1GAIN,
+		(b43_phy_read(dev, B43_PHY_N1P1GAIN) & ~0x000F) | 0x0008);
+	b43_phy_write(dev, B43_PHY_P1P2GAIN,
+		(b43_phy_read(dev, B43_PHY_P1P2GAIN) & ~0x0F00) | 0x0600);
+	b43_phy_write(dev, B43_PHY_N1N2GAIN,
+		(b43_phy_read(dev, B43_PHY_N1N2GAIN) & ~0x0F00) | 0x0700);
+	b43_phy_write(dev, B43_PHY_N1P1GAIN,
+		(b43_phy_read(dev, B43_PHY_N1P1GAIN) & ~0x0F00) | 0x0100);
+	if (phy->rev == 1) {
+		b43_phy_write(dev, B43_PHY_N1N2GAIN,
+				  (b43_phy_read(dev, B43_PHY_N1N2GAIN)
+				   & ~0x000F) | 0x0007);
+	}
+	b43_phy_write(dev, B43_PHY_OFDM(0x88),
+		(b43_phy_read(dev, B43_PHY_OFDM(0x88)) & ~0x00FF) | 0x001C);
+	b43_phy_write(dev, B43_PHY_OFDM(0x88),
+		(b43_phy_read(dev, B43_PHY_OFDM(0x88)) & ~0x3F00) | 0x0200);
+	b43_phy_write(dev, B43_PHY_OFDM(0x96),
+		(b43_phy_read(dev, B43_PHY_OFDM(0x96)) & ~0x00FF) | 0x001C);
+	b43_phy_write(dev, B43_PHY_OFDM(0x89),
+		(b43_phy_read(dev, B43_PHY_OFDM(0x89)) & ~0x00FF) | 0x0020);
+	b43_phy_write(dev, B43_PHY_OFDM(0x89),
+		(b43_phy_read(dev, B43_PHY_OFDM(0x89)) & ~0x3F00) | 0x0200);
+	b43_phy_write(dev, B43_PHY_OFDM(0x82),
+		(b43_phy_read(dev, B43_PHY_OFDM(0x82)) & ~0x00FF) | 0x002E);
+	b43_phy_write(dev, B43_PHY_OFDM(0x96),
+		(b43_phy_read(dev, B43_PHY_OFDM(0x96)) & ~0xFF00) | 0x1A00);
+	b43_phy_write(dev, B43_PHY_OFDM(0x81),
+		(b43_phy_read(dev, B43_PHY_OFDM(0x81)) & ~0x00FF) | 0x0028);
+	b43_phy_write(dev, B43_PHY_OFDM(0x81),
+		(b43_phy_read(dev, B43_PHY_OFDM(0x81)) & ~0xFF00) | 0x2C00);
+	if (phy->rev == 1) {
+		b43_phy_write(dev, B43_PHY_PEAK_COUNT, 0x092B);
+		b43_phy_write(dev, B43_PHY_OFDM(0x1B),
+			(b43_phy_read(dev, B43_PHY_OFDM(0x1B)) & ~0x001E) | 0x0002);
+	} else {
+		b43_phy_write(dev, B43_PHY_OFDM(0x1B),
+			b43_phy_read(dev, B43_PHY_OFDM(0x1B)) & ~0x001E);
+		b43_phy_write(dev, B43_PHY_OFDM(0x1F), 0x287A);
+		b43_phy_write(dev, B43_PHY_LPFGAINCTL,
+			(b43_phy_read(dev, B43_PHY_LPFGAINCTL) & ~0x000F) | 0x0004);
+		if (phy->rev >= 6) {
+			b43_phy_write(dev, B43_PHY_OFDM(0x22), 0x287A);
+			b43_phy_write(dev, B43_PHY_LPFGAINCTL,
+				(b43_phy_read(dev, B43_PHY_LPFGAINCTL) & ~0xF000) | 0x3000);
+		}
+	}
+	b43_phy_write(dev, B43_PHY_DIVSRCHIDX,
+		(b43_phy_read(dev, B43_PHY_DIVSRCHIDX) & 0x8080) | 0x7874);
+	b43_phy_write(dev, B43_PHY_OFDM(0x8E), 0x1C00);
+	if (phy->rev == 1) {
+		b43_phy_write(dev, B43_PHY_DIVP1P2GAIN,
+			(b43_phy_read(dev, B43_PHY_DIVP1P2GAIN) & ~0x0F00) | 0x0600);
+		b43_phy_write(dev, B43_PHY_OFDM(0x8B), 0x005E);
+		b43_phy_write(dev, B43_PHY_ANTWRSETT,
+			(b43_phy_read(dev, B43_PHY_ANTWRSETT) & ~0x00FF) | 0x001E);
+		b43_phy_write(dev, B43_PHY_OFDM(0x8D), 0x0002);
+		b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC3_R1, 0, 0);
+		b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC3_R1, 1, 7);
+		b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC3_R1, 2, 16);
+		b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC3_R1, 3, 28);
+	} else {
+		b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC3, 0, 0);
+		b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC3, 1, 7);
+		b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC3, 2, 16);
+		b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC3, 3, 28);
+	}
+	if (phy->rev >= 6) {
+		b43_phy_write(dev, B43_PHY_OFDM(0x26),
+			b43_phy_read(dev, B43_PHY_OFDM(0x26)) & ~0x0003);
+		b43_phy_write(dev, B43_PHY_OFDM(0x26),
+			b43_phy_read(dev, B43_PHY_OFDM(0x26)) & ~0x1000);
+	}
+	b43_phy_read(dev, B43_PHY_VERSION_OFDM); /* Dummy read */
+}
+
+static void b43_wa_tr_ltov(struct b43_wldev *dev) /* TR Lookup Table Original Values */
+{
+	b43_gtab_write(dev, B43_GTAB_ORIGTR, 0, 0xC480);
+}
+
+static void b43_wa_cpll_nonpilot(struct b43_wldev *dev)
+{
+	b43_ofdmtab_write16(dev, B43_OFDMTAB_UNKNOWN_11, 0, 0);
+	b43_ofdmtab_write16(dev, B43_OFDMTAB_UNKNOWN_11, 1, 0);
+}
+
+static void b43_wa_rssi_adc(struct b43_wldev *dev)
+{
+	if (dev->phy.analog == 4)
+		b43_phy_write(dev, 0x00DC, 0x7454);
+}
+
+static void b43_wa_boards_a(struct b43_wldev *dev)
+{
+	struct ssb_bus *bus = dev->dev->bus;
+
+	if (bus->boardinfo.vendor == SSB_BOARDVENDOR_BCM &&
+	    bus->boardinfo.type == SSB_BOARD_BU4306 &&
+	    bus->boardinfo.rev < 0x30) {
+		b43_phy_write(dev, 0x0010, 0xE000);
+		b43_phy_write(dev, 0x0013, 0x0140);
+		b43_phy_write(dev, 0x0014, 0x0280);
+	} else {
+		if (bus->boardinfo.type == SSB_BOARD_MP4318 &&
+		    bus->boardinfo.rev < 0x20) {
+			b43_phy_write(dev, 0x0013, 0x0210);
+			b43_phy_write(dev, 0x0014, 0x0840);
+		} else {
+			b43_phy_write(dev, 0x0013, 0x0140);
+			b43_phy_write(dev, 0x0014, 0x0280);
+		}
+		if (dev->phy.rev <= 4)
+			b43_phy_write(dev, 0x0010, 0xE000);
+		else
+			b43_phy_write(dev, 0x0010, 0x2000);
+		b43_ofdmtab_write16(dev, B43_OFDMTAB_DC, 1, 0x0039);
+		b43_ofdmtab_write16(dev, B43_OFDMTAB_UNKNOWN_APHY, 7, 0x0040);
+	}
+}
+
+static void b43_wa_boards_g(struct b43_wldev *dev)
+{
+	struct ssb_bus *bus = dev->dev->bus;
+	struct b43_phy *phy = &dev->phy;
+
+	if (bus->boardinfo.vendor != SSB_BOARDVENDOR_BCM ||
+	    bus->boardinfo.type != SSB_BOARD_BU4306 ||
+	    bus->boardinfo.rev != 0x17) {
+		if (phy->rev < 2) {
+			b43_ofdmtab_write16(dev, B43_OFDMTAB_GAINX_R1, 1, 0x0002);
+			b43_ofdmtab_write16(dev, B43_OFDMTAB_GAINX_R1, 2, 0x0001);
+		} else {
+			b43_ofdmtab_write16(dev, B43_OFDMTAB_GAINX, 1, 0x0002);
+			b43_ofdmtab_write16(dev, B43_OFDMTAB_GAINX, 2, 0x0001);
+			if ((bus->sprom.boardflags_lo & B43_BFL_EXTLNA) &&
+			    (phy->rev >= 7)) {
+				b43_phy_write(dev, B43_PHY_EXTG(0x11),
+					b43_phy_read(dev, B43_PHY_EXTG(0x11)) & 0xF7FF);
+				b43_ofdmtab_write16(dev, B43_OFDMTAB_GAINX, 0x0020, 0x0001);
+				b43_ofdmtab_write16(dev, B43_OFDMTAB_GAINX, 0x0021, 0x0001);
+				b43_ofdmtab_write16(dev, B43_OFDMTAB_GAINX, 0x0022, 0x0001);
+				b43_ofdmtab_write16(dev, B43_OFDMTAB_GAINX, 0x0023, 0x0000);
+				b43_ofdmtab_write16(dev, B43_OFDMTAB_GAINX, 0x0000, 0x0000);
+				b43_ofdmtab_write16(dev, B43_OFDMTAB_GAINX, 0x0003, 0x0002);
+			}
+		}
+	}
+	if (bus->sprom.boardflags_lo & B43_BFL_FEM) {
+		b43_phy_write(dev, B43_PHY_GTABCTL, 0x3120);
+		b43_phy_write(dev, B43_PHY_GTABDATA, 0xC480);
+	}
+}
+
+void b43_wa_all(struct b43_wldev *dev)
+{
+	struct b43_phy *phy = &dev->phy;
+
+	if (phy->type == B43_PHYTYPE_A) {
+		switch (phy->rev) {
+		case 2:
+			b43_wa_papd(dev);
+			b43_wa_auxclipthr(dev);
+			b43_wa_afcdac(dev);
+			b43_wa_txdc_offset(dev);
+			b43_wa_initgains(dev);
+			b43_wa_divider(dev);
+			b43_wa_gt(dev);
+			b43_wa_rssi_lt(dev);
+			b43_wa_analog(dev);
+			b43_wa_dac(dev);
+			b43_wa_fft(dev);
+			b43_wa_nft(dev);
+			b43_wa_rt(dev);
+			b43_wa_nst(dev);
+			b43_wa_art(dev);
+			b43_wa_txlna_gain(dev);
+			b43_wa_crs_reset(dev);
+			b43_wa_2060txlna_gain(dev);
+			b43_wa_lms(dev);
+			break;
+		case 3:
+			b43_wa_papd(dev);
+			b43_wa_mixedsignal(dev);
+			b43_wa_rssi_lt(dev);
+			b43_wa_txdc_offset(dev);
+			b43_wa_initgains(dev);
+			b43_wa_dac(dev);
+			b43_wa_nft(dev);
+			b43_wa_nst(dev);
+			b43_wa_msst(dev);
+			b43_wa_analog(dev);
+			b43_wa_gt(dev);
+			b43_wa_txpuoff_rxpuon(dev);
+			b43_wa_txlna_gain(dev);
+			break;
+		case 5:
+			b43_wa_iqadc(dev);
+		case 6:
+			b43_wa_papd(dev);
+			b43_wa_rssi_lt(dev);
+			b43_wa_txdc_offset(dev);
+			b43_wa_initgains(dev);
+			b43_wa_dac(dev);
+			b43_wa_nft(dev);
+			b43_wa_nst(dev);
+			b43_wa_msst(dev);
+			b43_wa_analog(dev);
+			b43_wa_gt(dev);
+			b43_wa_txpuoff_rxpuon(dev);
+			b43_wa_txlna_gain(dev);
+			break;
+		case 7:
+			b43_wa_iqadc(dev);
+			b43_wa_papd(dev);
+			b43_wa_rssi_lt(dev);
+			b43_wa_txdc_offset(dev);
+			b43_wa_initgains(dev);
+			b43_wa_dac(dev);
+			b43_wa_nft(dev);
+			b43_wa_nst(dev);
+			b43_wa_msst(dev);
+			b43_wa_analog(dev);
+			b43_wa_gt(dev);
+			b43_wa_txpuoff_rxpuon(dev);
+			b43_wa_txlna_gain(dev);
+			b43_wa_rssi_adc(dev);
+		default:
+			B43_WARN_ON(1);
+		}
+		b43_wa_boards_a(dev);
+	} else if (phy->type == B43_PHYTYPE_G) {
+		switch (phy->rev) {
+		case 1://XXX review rev1
+			b43_wa_crs_ed(dev);
+			b43_wa_crs_thr(dev);
+			b43_wa_crs_blank(dev);
+			b43_wa_cck_shiftbits(dev);
+			b43_wa_fft(dev);
+			b43_wa_nft(dev);
+			b43_wa_rt(dev);
+			b43_wa_nst(dev);
+			b43_wa_art(dev);
+			b43_wa_wrssi_offset(dev);
+			b43_wa_altagc(dev);
+			break;
+		case 2:
+		case 6:
+		case 7:
+		case 8:
+		case 9:
+			b43_wa_tr_ltov(dev);
+			b43_wa_crs_ed(dev);
+			b43_wa_rssi_lt(dev);
+			b43_wa_nft(dev);
+			b43_wa_nst(dev);
+			b43_wa_msst(dev);
+			b43_wa_wrssi_offset(dev);
+			b43_wa_altagc(dev);
+			b43_wa_analog(dev);
+			b43_wa_txpuoff_rxpuon(dev);
+			break;
+		default:
+			B43_WARN_ON(1);
+		}
+		b43_wa_boards_g(dev);
+	} else { /* No N PHY support so far */
+		B43_WARN_ON(1);
+	}
+
+	b43_wa_cpll_nonpilot(dev);
+}
diff --git a/package/b43/src/wa.h b/package/b43/src/wa.h
new file mode 100644
index 0000000000..e163c5e56e
--- /dev/null
+++ b/package/b43/src/wa.h
@@ -0,0 +1,7 @@
+#ifndef B43_WA_H_
+#define B43_WA_H_
+
+void b43_wa_initgains(struct b43_wldev *dev);
+void b43_wa_all(struct b43_wldev *dev);
+
+#endif /* B43_WA_H_ */
diff --git a/package/b43/src/xmit.c b/package/b43/src/xmit.c
index 0bd6f8a348..4014b6c827 100644
--- a/package/b43/src/xmit.c
+++ b/package/b43/src/xmit.c
@@ -5,7 +5,7 @@
   Transmission (TX/RX) related functions.
 
   Copyright (C) 2005 Martin Langer <martin-langer@gmx.de>
-  Copyright (C) 2005 Stefano Brivio <st3@riseup.net>
+  Copyright (C) 2005 Stefano Brivio <stefano.brivio@polimi.it>
   Copyright (C) 2005, 2006 Michael Buesch <mb@bu3sch.de>
   Copyright (C) 2005 Danny van Dyk <kugelfang@gentoo.org>
   Copyright (C) 2005 Andreas Jaggi <andreas.jaggi@waterwave.ch>
@@ -30,48 +30,50 @@
 #include "xmit.h"
 #include "phy.h"
 #include "dma.h"
-#include "pio.h"
 
-/* Extract the bitrate out of a CCK PLCP header. */
-static u8 b43_plcp_get_bitrate_cck(struct b43_plcp_hdr6 *plcp)
+
+/* Extract the bitrate index out of a CCK PLCP header. */
+static int b43_plcp_get_bitrate_idx_cck(struct b43_plcp_hdr6 *plcp)
 {
 	switch (plcp->raw[0]) {
 	case 0x0A:
-		return B43_CCK_RATE_1MB;
+		return 0;
 	case 0x14:
-		return B43_CCK_RATE_2MB;
+		return 1;
 	case 0x37:
-		return B43_CCK_RATE_5MB;
+		return 2;
 	case 0x6E:
-		return B43_CCK_RATE_11MB;
+		return 3;
 	}
 	B43_WARN_ON(1);
-	return 0;
+	return -1;
 }
 
-/* Extract the bitrate out of an OFDM PLCP header. */
-static u8 b43_plcp_get_bitrate_ofdm(struct b43_plcp_hdr6 *plcp)
+/* Extract the bitrate index out of an OFDM PLCP header. */
+static u8 b43_plcp_get_bitrate_idx_ofdm(struct b43_plcp_hdr6 *plcp, bool aphy)
 {
+	int base = aphy ? 0 : 4;
+
 	switch (plcp->raw[0] & 0xF) {
 	case 0xB:
-		return B43_OFDM_RATE_6MB;
+		return base + 0;
 	case 0xF:
-		return B43_OFDM_RATE_9MB;
+		return base + 1;
 	case 0xA:
-		return B43_OFDM_RATE_12MB;
+		return base + 2;
 	case 0xE:
-		return B43_OFDM_RATE_18MB;
+		return base + 3;
 	case 0x9:
-		return B43_OFDM_RATE_24MB;
+		return base + 4;
 	case 0xD:
-		return B43_OFDM_RATE_36MB;
+		return base + 5;
 	case 0x8:
-		return B43_OFDM_RATE_48MB;
+		return base + 6;
 	case 0xC:
-		return B43_OFDM_RATE_54MB;
+		return base + 7;
 	}
 	B43_WARN_ON(1);
-	return 0;
+	return -1;
 }
 
 u8 b43_plcp_get_ratecode_cck(const u8 bitrate)
@@ -177,18 +179,21 @@ static u8 b43_calc_fallback_rate(u8 bitrate)
 	return 0;
 }
 
-static void generate_txhdr_fw4(struct b43_wldev *dev,
-			       struct b43_txhdr_fw4 *txhdr,
-			       const unsigned char *fragment_data,
-			       unsigned int fragment_len,
-			       const struct ieee80211_tx_control *txctl,
-			       u16 cookie)
+/* Generate a TX data header. */
+int b43_generate_txhdr(struct b43_wldev *dev,
+		       u8 *_txhdr,
+		       const unsigned char *fragment_data,
+		       unsigned int fragment_len,
+		       const struct ieee80211_tx_control *txctl,
+		       u16 cookie)
 {
+	struct b43_txhdr *txhdr = (struct b43_txhdr *)_txhdr;
 	const struct b43_phy *phy = &dev->phy;
 	const struct ieee80211_hdr *wlhdr =
 	    (const struct ieee80211_hdr *)fragment_data;
 	int use_encryption = (!(txctl->flags & IEEE80211_TXCTL_DO_NOT_ENCRYPT));
 	u16 fctl = le16_to_cpu(wlhdr->frame_control);
+	struct ieee80211_rate *fbrate;
 	u8 rate, rate_fb;
 	int rate_ofdm, rate_fb_ofdm;
 	unsigned int plcp_fragment_len;
@@ -198,9 +203,11 @@ static void generate_txhdr_fw4(struct b43_wldev *dev,
 
 	memset(txhdr, 0, sizeof(*txhdr));
 
-	rate = txctl->tx_rate;
+	WARN_ON(!txctl->tx_rate);
+	rate = txctl->tx_rate ? txctl->tx_rate->hw_value : B43_CCK_RATE_1MB;
 	rate_ofdm = b43_is_ofdm_rate(rate);
-	rate_fb = (txctl->alt_retry_rate == -1) ? rate : txctl->alt_retry_rate;
+	fbrate = txctl->alt_retry_rate ? : txctl->tx_rate;
+	rate_fb = fbrate->hw_value;
 	rate_fb_ofdm = b43_is_ofdm_rate(rate_fb);
 
 	if (rate_ofdm)
@@ -219,11 +226,10 @@ static void generate_txhdr_fw4(struct b43_wldev *dev,
 		 * use the original dur_id field. */
 		txhdr->dur_fb = wlhdr->duration_id;
 	} else {
-		int fbrate_base100kbps = B43_RATE_TO_BASE100KBPS(rate_fb);
 		txhdr->dur_fb = ieee80211_generic_frame_duration(dev->wl->hw,
-								 dev->wl->if_id,
+								 txctl->vif,
 								 fragment_len,
-								 fbrate_base100kbps);
+								 fbrate);
 	}
 
 	plcp_fragment_len = fragment_len + FCS_LEN;
@@ -235,29 +241,44 @@ static void generate_txhdr_fw4(struct b43_wldev *dev,
 
 		B43_WARN_ON(key_idx >= dev->max_nr_keys);
 		key = &(dev->key[key_idx]);
-		B43_WARN_ON(!key->keyconf);
+
+		if (unlikely(!key->keyconf)) {
+			/* This key is invalid. This might only happen
+			 * in a short timeframe after machine resume before
+			 * we were able to reconfigure keys.
+			 * Drop this packet completely. Do not transmit it
+			 * unencrypted to avoid leaking information. */
+			return -ENOKEY;
+		}
 
 		/* Hardware appends ICV. */
 		plcp_fragment_len += txctl->icv_len;
 
 		key_idx = b43_kidx_to_fw(dev, key_idx);
-		mac_ctl |= (key_idx << B43_TX4_MAC_KEYIDX_SHIFT) &
-			   B43_TX4_MAC_KEYIDX;
-		mac_ctl |= (key->algorithm << B43_TX4_MAC_KEYALG_SHIFT) &
-			   B43_TX4_MAC_KEYALG;
+		mac_ctl |= (key_idx << B43_TXH_MAC_KEYIDX_SHIFT) &
+			   B43_TXH_MAC_KEYIDX;
+		mac_ctl |= (key->algorithm << B43_TXH_MAC_KEYALG_SHIFT) &
+			   B43_TXH_MAC_KEYALG;
 		wlhdr_len = ieee80211_get_hdrlen(fctl);
 		iv_len = min((size_t) txctl->iv_len,
 			     ARRAY_SIZE(txhdr->iv));
 		memcpy(txhdr->iv, ((u8 *) wlhdr) + wlhdr_len, iv_len);
 	}
-	b43_generate_plcp_hdr((struct b43_plcp_hdr4 *)(&txhdr->plcp),
-			      plcp_fragment_len, rate);
+	if (b43_is_old_txhdr_format(dev)) {
+		b43_generate_plcp_hdr((struct b43_plcp_hdr4 *)(&txhdr->old_format.plcp),
+				      plcp_fragment_len, rate);
+	} else {
+		b43_generate_plcp_hdr((struct b43_plcp_hdr4 *)(&txhdr->new_format.plcp),
+				      plcp_fragment_len, rate);
+	}
 	b43_generate_plcp_hdr((struct b43_plcp_hdr4 *)(&txhdr->plcp_fb),
 			      plcp_fragment_len, rate_fb);
 
 	/* Extra Frame Types */
 	if (rate_fb_ofdm)
-		extra_ft |= B43_TX4_EFT_FBOFDM;
+		extra_ft |= B43_TXH_EFT_FB_OFDM;
+	else
+		extra_ft |= B43_TXH_EFT_FB_CCK;
 
 	/* Set channel radio code. Note that the micrcode ORs 0x100 to
 	 * this value before comparing it to the value in SHM, if this
@@ -267,18 +288,27 @@ static void generate_txhdr_fw4(struct b43_wldev *dev,
 
 	/* PHY TX Control word */
 	if (rate_ofdm)
-		phy_ctl |= B43_TX4_PHY_OFDM;
-	if (dev->short_preamble)
-		phy_ctl |= B43_TX4_PHY_SHORTPRMBL;
-	switch (txctl->antenna_sel_tx) {
-	case 0:
-		phy_ctl |= B43_TX4_PHY_ANTLAST;
+		phy_ctl |= B43_TXH_PHY_ENC_OFDM;
+	else
+		phy_ctl |= B43_TXH_PHY_ENC_CCK;
+	if (txctl->flags & IEEE80211_TXCTL_SHORT_PREAMBLE)
+		phy_ctl |= B43_TXH_PHY_SHORTPRMBL;
+
+	switch (b43_ieee80211_antenna_sanitize(dev, txctl->antenna_sel_tx)) {
+	case 0: /* Default */
+		phy_ctl |= B43_TXH_PHY_ANT01AUTO;
 		break;
-	case 1:
-		phy_ctl |= B43_TX4_PHY_ANT0;
+	case 1: /* Antenna 0 */
+		phy_ctl |= B43_TXH_PHY_ANT0;
 		break;
-	case 2:
-		phy_ctl |= B43_TX4_PHY_ANT1;
+	case 2: /* Antenna 1 */
+		phy_ctl |= B43_TXH_PHY_ANT1;
+		break;
+	case 3: /* Antenna 2 */
+		phy_ctl |= B43_TXH_PHY_ANT2;
+		break;
+	case 4: /* Antenna 3 */
+		phy_ctl |= B43_TXH_PHY_ANT3;
 		break;
 	default:
 		B43_WARN_ON(1);
@@ -286,14 +316,16 @@ static void generate_txhdr_fw4(struct b43_wldev *dev,
 
 	/* MAC control */
 	if (!(txctl->flags & IEEE80211_TXCTL_NO_ACK))
-		mac_ctl |= B43_TX4_MAC_ACK;
+		mac_ctl |= B43_TXH_MAC_ACK;
 	if (!(((fctl & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_CTL) &&
 	      ((fctl & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_PSPOLL)))
-		mac_ctl |= B43_TX4_MAC_HWSEQ;
+		mac_ctl |= B43_TXH_MAC_HWSEQ;
 	if (txctl->flags & IEEE80211_TXCTL_FIRST_FRAGMENT)
-		mac_ctl |= B43_TX4_MAC_STMSDU;
+		mac_ctl |= B43_TXH_MAC_STMSDU;
 	if (phy->type == B43_PHYTYPE_A)
-		mac_ctl |= B43_TX4_MAC_5GHZ;
+		mac_ctl |= B43_TXH_MAC_5GHZ;
+	if (txctl->flags & IEEE80211_TXCTL_LONG_RETRY_LIMIT)
+		mac_ctl |= B43_TXH_MAC_LONGFRAME;
 
 	/* Generate the RTS or CTS-to-self frame */
 	if ((txctl->flags & IEEE80211_TXCTL_USE_RTS_CTS) ||
@@ -302,66 +334,94 @@ static void generate_txhdr_fw4(struct b43_wldev *dev,
 		struct ieee80211_hdr *hdr;
 		int rts_rate, rts_rate_fb;
 		int rts_rate_ofdm, rts_rate_fb_ofdm;
+		struct b43_plcp_hdr6 *plcp;
 
-		rts_rate = txctl->rts_cts_rate;
+		WARN_ON(!txctl->rts_cts_rate);
+		rts_rate = txctl->rts_cts_rate ? txctl->rts_cts_rate->hw_value : B43_CCK_RATE_1MB;
 		rts_rate_ofdm = b43_is_ofdm_rate(rts_rate);
 		rts_rate_fb = b43_calc_fallback_rate(rts_rate);
 		rts_rate_fb_ofdm = b43_is_ofdm_rate(rts_rate_fb);
 
 		if (txctl->flags & IEEE80211_TXCTL_USE_CTS_PROTECT) {
-			ieee80211_ctstoself_get(dev->wl->hw, dev->wl->if_id,
+			struct ieee80211_cts *cts;
+
+			if (b43_is_old_txhdr_format(dev)) {
+				cts = (struct ieee80211_cts *)
+					(txhdr->old_format.rts_frame);
+			} else {
+				cts = (struct ieee80211_cts *)
+					(txhdr->new_format.rts_frame);
+			}
+			ieee80211_ctstoself_get(dev->wl->hw, txctl->vif,
 						fragment_data, fragment_len,
-						txctl,
-						(struct ieee80211_cts *)(txhdr->
-									 rts_frame));
-			mac_ctl |= B43_TX4_MAC_SENDCTS;
+						txctl, cts);
+			mac_ctl |= B43_TXH_MAC_SENDCTS;
 			len = sizeof(struct ieee80211_cts);
 		} else {
-			ieee80211_rts_get(dev->wl->hw, dev->wl->if_id,
-					  fragment_data, fragment_len, txctl,
-					  (struct ieee80211_rts *)(txhdr->
-								   rts_frame));
-			mac_ctl |= B43_TX4_MAC_SENDRTS;
+			struct ieee80211_rts *rts;
+
+			if (b43_is_old_txhdr_format(dev)) {
+				rts = (struct ieee80211_rts *)
+					(txhdr->old_format.rts_frame);
+			} else {
+				rts = (struct ieee80211_rts *)
+					(txhdr->new_format.rts_frame);
+			}
+			ieee80211_rts_get(dev->wl->hw, txctl->vif,
+					  fragment_data, fragment_len,
+					  txctl, rts);
+			mac_ctl |= B43_TXH_MAC_SENDRTS;
 			len = sizeof(struct ieee80211_rts);
 		}
 		len += FCS_LEN;
-		b43_generate_plcp_hdr((struct b43_plcp_hdr4 *)(&txhdr->
-							       rts_plcp), len,
-				      rts_rate);
-		b43_generate_plcp_hdr((struct b43_plcp_hdr4 *)(&txhdr->
-							       rts_plcp_fb),
+
+		/* Generate the PLCP headers for the RTS/CTS frame */
+		if (b43_is_old_txhdr_format(dev))
+			plcp = &txhdr->old_format.rts_plcp;
+		else
+			plcp = &txhdr->new_format.rts_plcp;
+		b43_generate_plcp_hdr((struct b43_plcp_hdr4 *)plcp,
+				      len, rts_rate);
+		plcp = &txhdr->rts_plcp_fb;
+		b43_generate_plcp_hdr((struct b43_plcp_hdr4 *)plcp,
 				      len, rts_rate_fb);
-		hdr = (struct ieee80211_hdr *)(&txhdr->rts_frame);
+
+		if (b43_is_old_txhdr_format(dev)) {
+			hdr = (struct ieee80211_hdr *)
+				(&txhdr->old_format.rts_frame);
+		} else {
+			hdr = (struct ieee80211_hdr *)
+				(&txhdr->new_format.rts_frame);
+		}
 		txhdr->rts_dur_fb = hdr->duration_id;
+
 		if (rts_rate_ofdm) {
-			extra_ft |= B43_TX4_EFT_RTSOFDM;
+			extra_ft |= B43_TXH_EFT_RTS_OFDM;
 			txhdr->phy_rate_rts =
 			    b43_plcp_get_ratecode_ofdm(rts_rate);
-		} else
+		} else {
+			extra_ft |= B43_TXH_EFT_RTS_CCK;
 			txhdr->phy_rate_rts =
 			    b43_plcp_get_ratecode_cck(rts_rate);
+		}
 		if (rts_rate_fb_ofdm)
-			extra_ft |= B43_TX4_EFT_RTSFBOFDM;
-		mac_ctl |= B43_TX4_MAC_LONGFRAME;
+			extra_ft |= B43_TXH_EFT_RTSFB_OFDM;
+		else
+			extra_ft |= B43_TXH_EFT_RTSFB_CCK;
 	}
 
 	/* Magic cookie */
-	txhdr->cookie = cpu_to_le16(cookie);
+	if (b43_is_old_txhdr_format(dev))
+		txhdr->old_format.cookie = cpu_to_le16(cookie);
+	else
+		txhdr->new_format.cookie = cpu_to_le16(cookie);
 
 	/* Apply the bitfields */
 	txhdr->mac_ctl = cpu_to_le32(mac_ctl);
 	txhdr->phy_ctl = cpu_to_le16(phy_ctl);
 	txhdr->extra_ft = extra_ft;
-}
 
-void b43_generate_txhdr(struct b43_wldev *dev,
-			u8 * txhdr,
-			const unsigned char *fragment_data,
-			unsigned int fragment_len,
-			const struct ieee80211_tx_control *txctl, u16 cookie)
-{
-	generate_txhdr_fw4(dev, (struct b43_txhdr_fw4 *)txhdr,
-			   fragment_data, fragment_len, txctl, cookie);
+	return 0;
 }
 
 static s8 b43_rssi_postprocess(struct b43_wldev *dev,
@@ -384,7 +444,7 @@ static s8 b43_rssi_postprocess(struct b43_wldev *dev,
 			else
 				tmp -= 3;
 		} else {
-			if (dev->dev->bus->sprom.r1.
+			if (dev->dev->bus->sprom.
 			    boardflags_lo & B43_BFL_RSSI) {
 				if (in_rssi > 63)
 					in_rssi = 63;
@@ -451,6 +511,7 @@ void b43_rx(struct b43_wldev *dev, struct sk_buff *skb, const void *_rxhdr)
 	u16 phystat0, phystat3, chanstat, mactime;
 	u32 macstat;
 	u16 chanid;
+	u16 phytype;
 	u8 jssi;
 	int padding;
 
@@ -463,6 +524,7 @@ void b43_rx(struct b43_wldev *dev, struct sk_buff *skb, const void *_rxhdr)
 	macstat = le32_to_cpu(rxhdr->mac_status);
 	mactime = le16_to_cpu(rxhdr->mac_time);
 	chanstat = le16_to_cpu(rxhdr->channel);
+	phytype = chanstat & B43_RX_CHAN_PHYTYPE;
 
 	if (macstat & B43_RX_MAC_FCSERR)
 		dev->wl->ieee_stats.dot11FCSErrorCount++;
@@ -488,7 +550,6 @@ void b43_rx(struct b43_wldev *dev, struct sk_buff *skb, const void *_rxhdr)
 	}
 	wlhdr = (struct ieee80211_hdr *)(skb->data);
 	fctl = le16_to_cpu(wlhdr->frame_control);
-	skb_trim(skb, skb->len - FCS_LEN);
 
 	if (macstat & B43_RX_MAC_DEC) {
 		unsigned int keyidx;
@@ -521,31 +582,59 @@ void b43_rx(struct b43_wldev *dev, struct sk_buff *skb, const void *_rxhdr)
 	/* the next line looks wrong, but is what mac80211 wants */
 	status.signal = (jssi * 100) / B43_RX_MAX_SSI;
 	if (phystat0 & B43_RX_PHYST0_OFDM)
-		status.rate = b43_plcp_get_bitrate_ofdm(plcp);
+		status.rate_idx = b43_plcp_get_bitrate_idx_ofdm(plcp,
+						phytype == B43_PHYTYPE_A);
 	else
-		status.rate = b43_plcp_get_bitrate_cck(plcp);
+		status.rate_idx = b43_plcp_get_bitrate_idx_cck(plcp);
 	status.antenna = !!(phystat0 & B43_RX_PHYST0_ANT);
-	status.mactime = mactime;
+
+	/*
+	 * If monitors are present get full 64-bit timestamp. This
+	 * code assumes we get to process the packet within 16 bits
+	 * of timestamp, i.e. about 65 milliseconds after the PHY
+	 * received the first symbol.
+	 */
+	if (dev->wl->radiotap_enabled) {
+		u16 low_mactime_now;
+
+		b43_tsf_read(dev, &status.mactime);
+		low_mactime_now = status.mactime;
+		status.mactime = status.mactime & ~0xFFFFULL;
+		status.mactime += mactime;
+		if (low_mactime_now <= mactime)
+			status.mactime -= 0x10000;
+		status.flag |= RX_FLAG_TSFT;
+	}
 
 	chanid = (chanstat & B43_RX_CHAN_ID) >> B43_RX_CHAN_ID_SHIFT;
 	switch (chanstat & B43_RX_CHAN_PHYTYPE) {
 	case B43_PHYTYPE_A:
-		status.phymode = MODE_IEEE80211A;
-		status.freq = chanid;
-		status.channel = b43_freq_to_channel_a(chanid);
-		break;
-	case B43_PHYTYPE_B:
-		status.phymode = MODE_IEEE80211B;
-		status.freq = chanid + 2400;
-		status.channel = b43_freq_to_channel_bg(chanid + 2400);
+		status.band = IEEE80211_BAND_5GHZ;
+		B43_WARN_ON(1);
+		/* FIXME: We don't really know which value the "chanid" contains.
+		 *        So the following assignment might be wrong. */
+		status.freq = b43_channel_to_freq_5ghz(chanid);
 		break;
 	case B43_PHYTYPE_G:
-		status.phymode = MODE_IEEE80211G;
+		status.band = IEEE80211_BAND_2GHZ;
+		/* chanid is the radio channel cookie value as used
+		 * to tune the radio. */
 		status.freq = chanid + 2400;
-		status.channel = b43_freq_to_channel_bg(chanid + 2400);
+		break;
+	case B43_PHYTYPE_N:
+		/* chanid is the SHM channel cookie. Which is the plain
+		 * channel number in b43. */
+		if (chanstat & B43_RX_CHAN_5GHZ) {
+			status.band = IEEE80211_BAND_5GHZ;
+			status.freq = b43_freq_to_channel_5ghz(chanid);
+		} else {
+			status.band = IEEE80211_BAND_2GHZ;
+			status.freq = b43_freq_to_channel_2ghz(chanid);
+		}
 		break;
 	default:
 		B43_WARN_ON(1);
+		goto drop;
 	}
 
 	dev->stats.last_rx = jiffies;
@@ -575,10 +664,7 @@ void b43_handle_txstatus(struct b43_wldev *dev,
 			dev->wl->ieee_stats.dot11RTSSuccessCount++;
 	}
 
-	if (b43_using_pio(dev))
-		b43_pio_handle_txstatus(dev, status);
-	else
-		b43_dma_handle_txstatus(dev, status);
+	b43_dma_handle_txstatus(dev, status);
 }
 
 /* Handle TX status report as received through DMA/PIO queues */
@@ -607,19 +693,13 @@ void b43_handle_hwtxstatus(struct b43_wldev *dev,
 /* Stop any TX operation on the device (suspend the hardware queues) */
 void b43_tx_suspend(struct b43_wldev *dev)
 {
-	if (b43_using_pio(dev))
-		b43_pio_freeze_txqueues(dev);
-	else
-		b43_dma_tx_suspend(dev);
+	b43_dma_tx_suspend(dev);
 }
 
 /* Resume any TX operation on the device (resume the hardware queues) */
 void b43_tx_resume(struct b43_wldev *dev)
 {
-	if (b43_using_pio(dev))
-		b43_pio_thaw_txqueues(dev);
-	else
-		b43_dma_tx_resume(dev);
+	b43_dma_tx_resume(dev);
 }
 
 #if 0
diff --git a/package/b43/src/xmit.h b/package/b43/src/xmit.h
index 03bddd2516..4176503955 100644
--- a/package/b43/src/xmit.h
+++ b/package/b43/src/xmit.h
@@ -19,74 +19,166 @@ _b43_declare_plcp_hdr(6);
 #undef _b43_declare_plcp_hdr
 
 /* TX header for v4 firmware */
-struct b43_txhdr_fw4 {
-	__le32 mac_ctl;		/* MAC TX control */
-	__le16 mac_frame_ctl;	/* Copy of the FrameControl field */
+struct b43_txhdr {
+	__le32 mac_ctl;			/* MAC TX control */
+	__le16 mac_frame_ctl;		/* Copy of the FrameControl field */
 	__le16 tx_fes_time_norm;	/* TX FES Time Normal */
-	__le16 phy_ctl;		/* PHY TX control */
-	__le16 phy_ctl_0;	/* Unused */
-	__le16 phy_ctl_1;	/* Unused */
-	__le16 phy_ctl_rts_0;	/* Unused */
-	__le16 phy_ctl_rts_1;	/* Unused */
-	__u8 phy_rate;		/* PHY rate */
-	__u8 phy_rate_rts;	/* PHY rate for RTS/CTS */
-	__u8 extra_ft;		/* Extra Frame Types */
-	__u8 chan_radio_code;	/* Channel Radio Code */
-	__u8 iv[16];		/* Encryption IV */
-	__u8 tx_receiver[6];	/* TX Frame Receiver address */
-	__le16 tx_fes_time_fb;	/* TX FES Time Fallback */
-	struct b43_plcp_hdr6 rts_plcp_fb;	/* RTS fallback PLCP */
-	__le16 rts_dur_fb;	/* RTS fallback duration */
-	struct b43_plcp_hdr6 plcp_fb;	/* Fallback PLCP */
-	__le16 dur_fb;		/* Fallback duration */
-	__le16 mm_dur_time;	/* Unused */
-	__le16 mm_dur_time_fb;	/* Unused */
-	__le32 time_stamp;	/* Timestamp */
-	 PAD_BYTES(2);
-	__le16 cookie;		/* TX frame cookie */
-	__le16 tx_status;	/* TX status */
-	struct b43_plcp_hdr6 rts_plcp;	/* RTS PLCP */
-	__u8 rts_frame[16];	/* The RTS frame (if used) */
-	 PAD_BYTES(2);
-	struct b43_plcp_hdr6 plcp;	/* Main PLCP */
+	__le16 phy_ctl;			/* PHY TX control */
+	__le16 phy_ctl1;		/* PHY TX control word 1 */
+	__le16 phy_ctl1_fb;		/* PHY TX control word 1 for fallback rates */
+	__le16 phy_ctl1_rts;		/* PHY TX control word 1 RTS */
+	__le16 phy_ctl1_rts_fb;		/* PHY TX control word 1 RTS for fallback rates */
+	__u8 phy_rate;			/* PHY rate */
+	__u8 phy_rate_rts;		/* PHY rate for RTS/CTS */
+	__u8 extra_ft;			/* Extra Frame Types */
+	__u8 chan_radio_code;		/* Channel Radio Code */
+	__u8 iv[16];			/* Encryption IV */
+	__u8 tx_receiver[6];		/* TX Frame Receiver address */
+	__le16 tx_fes_time_fb;		/* TX FES Time Fallback */
+	struct b43_plcp_hdr6 rts_plcp_fb; /* RTS fallback PLCP header */
+	__le16 rts_dur_fb;		/* RTS fallback duration */
+	struct b43_plcp_hdr6 plcp_fb;	/* Fallback PLCP header */
+	__le16 dur_fb;			/* Fallback duration */
+	__le16 mimo_modelen;		/* MIMO mode length */
+	__le16 mimo_ratelen_fb;		/* MIMO fallback rate length */
+	__le32 timeout;			/* Timeout */
+
+	union {
+		/* The new r410 format. */
+		struct {
+			__le16 mimo_antenna;		/* MIMO antenna select */
+			__le16 preload_size;		/* Preload size */
+			PAD_BYTES(2);
+			__le16 cookie;			/* TX frame cookie */
+			__le16 tx_status;		/* TX status */
+			struct b43_plcp_hdr6 rts_plcp;	/* RTS PLCP header */
+			__u8 rts_frame[16];		/* The RTS frame (if used) */
+			PAD_BYTES(2);
+			struct b43_plcp_hdr6 plcp;	/* Main PLCP header */
+		} new_format __attribute__ ((__packed__));
+
+		/* The old r351 format. */
+		struct {
+			PAD_BYTES(2);
+			__le16 cookie;			/* TX frame cookie */
+			__le16 tx_status;		/* TX status */
+			struct b43_plcp_hdr6 rts_plcp;	/* RTS PLCP header */
+			__u8 rts_frame[16];		/* The RTS frame (if used) */
+			PAD_BYTES(2);
+			struct b43_plcp_hdr6 plcp;	/* Main PLCP header */
+		} old_format __attribute__ ((__packed__));
+
+	} __attribute__ ((__packed__));
 } __attribute__ ((__packed__));
 
 /* MAC TX control */
-#define B43_TX4_MAC_KEYIDX		0x0FF00000	/* Security key index */
-#define B43_TX4_MAC_KEYIDX_SHIFT	20
-#define B43_TX4_MAC_KEYALG		0x00070000	/* Security key algorithm */
-#define B43_TX4_MAC_KEYALG_SHIFT	16
-#define B43_TX4_MAC_LIFETIME	0x00001000
-#define B43_TX4_MAC_FRAMEBURST	0x00000800
-#define B43_TX4_MAC_SENDCTS		0x00000400
-#define B43_TX4_MAC_AMPDU		0x00000300
-#define B43_TX4_MAC_AMPDU_SHIFT	8
-#define B43_TX4_MAC_5GHZ		0x00000080
-#define B43_TX4_MAC_IGNPMQ		0x00000020
-#define B43_TX4_MAC_HWSEQ		0x00000010	/* Use Hardware Sequence Number */
-#define B43_TX4_MAC_STMSDU		0x00000008	/* Start MSDU */
-#define B43_TX4_MAC_SENDRTS		0x00000004
-#define B43_TX4_MAC_LONGFRAME	0x00000002
-#define B43_TX4_MAC_ACK		0x00000001
+#define B43_TXH_MAC_USEFBR		0x10000000 /* Use fallback rate for this AMPDU */
+#define B43_TXH_MAC_KEYIDX		0x0FF00000 /* Security key index */
+#define B43_TXH_MAC_KEYIDX_SHIFT	20
+#define B43_TXH_MAC_KEYALG		0x00070000 /* Security key algorithm */
+#define B43_TXH_MAC_KEYALG_SHIFT	16
+#define B43_TXH_MAC_AMIC		0x00008000 /* AMIC */
+#define B43_TXH_MAC_RIFS		0x00004000 /* Use RIFS */
+#define B43_TXH_MAC_LIFETIME		0x00002000 /* Lifetime */
+#define B43_TXH_MAC_FRAMEBURST		0x00001000 /* Frameburst */
+#define B43_TXH_MAC_SENDCTS		0x00000800 /* Send CTS-to-self */
+#define B43_TXH_MAC_AMPDU		0x00000600 /* AMPDU status */
+#define  B43_TXH_MAC_AMPDU_MPDU		0x00000000 /* Regular MPDU, not an AMPDU */
+#define  B43_TXH_MAC_AMPDU_FIRST	0x00000200 /* First MPDU or AMPDU */
+#define  B43_TXH_MAC_AMPDU_INTER	0x00000400 /* Intermediate MPDU or AMPDU */
+#define  B43_TXH_MAC_AMPDU_LAST		0x00000600 /* Last (or only) MPDU of AMPDU */
+#define B43_TXH_MAC_40MHZ		0x00000100 /* Use 40 MHz bandwidth */
+#define B43_TXH_MAC_5GHZ		0x00000080 /* 5GHz band */
+#define B43_TXH_MAC_DFCS		0x00000040 /* DFCS */
+#define B43_TXH_MAC_IGNPMQ		0x00000020 /* Ignore PMQ */
+#define B43_TXH_MAC_HWSEQ		0x00000010 /* Use Hardware Sequence Number */
+#define B43_TXH_MAC_STMSDU		0x00000008 /* Start MSDU */
+#define B43_TXH_MAC_SENDRTS		0x00000004 /* Send RTS */
+#define B43_TXH_MAC_LONGFRAME		0x00000002 /* Long frame */
+#define B43_TXH_MAC_ACK			0x00000001 /* Immediate ACK */
 
 /* Extra Frame Types */
-#define B43_TX4_EFT_FBOFDM		0x0001	/* Data frame fallback rate type */
-#define B43_TX4_EFT_RTSOFDM		0x0004	/* RTS/CTS rate type */
-#define B43_TX4_EFT_RTSFBOFDM	0x0010	/* RTS/CTS fallback rate type */
+#define B43_TXH_EFT_FB			0x03 /* Data frame fallback encoding */
+#define  B43_TXH_EFT_FB_CCK		0x00 /* CCK */
+#define  B43_TXH_EFT_FB_OFDM		0x01 /* OFDM */
+#define  B43_TXH_EFT_FB_EWC		0x02 /* EWC */
+#define  B43_TXH_EFT_FB_N		0x03 /* N */
+#define B43_TXH_EFT_RTS			0x0C /* RTS/CTS encoding */
+#define  B43_TXH_EFT_RTS_CCK		0x00 /* CCK */
+#define  B43_TXH_EFT_RTS_OFDM		0x04 /* OFDM */
+#define  B43_TXH_EFT_RTS_EWC		0x08 /* EWC */
+#define  B43_TXH_EFT_RTS_N		0x0C /* N */
+#define B43_TXH_EFT_RTSFB		0x30 /* RTS/CTS fallback encoding */
+#define  B43_TXH_EFT_RTSFB_CCK		0x00 /* CCK */
+#define  B43_TXH_EFT_RTSFB_OFDM		0x10 /* OFDM */
+#define  B43_TXH_EFT_RTSFB_EWC		0x20 /* EWC */
+#define  B43_TXH_EFT_RTSFB_N		0x30 /* N */
 
 /* PHY TX control word */
-#define B43_TX4_PHY_OFDM		0x0001	/* Data frame rate type */
-#define B43_TX4_PHY_SHORTPRMBL	0x0010	/* Use short preamble */
-#define B43_TX4_PHY_ANT		0x03C0	/* Antenna selection */
-#define  B43_TX4_PHY_ANT0		0x0000	/* Use antenna 0 */
-#define  B43_TX4_PHY_ANT1		0x0100	/* Use antenna 1 */
-#define  B43_TX4_PHY_ANTLAST	0x0300	/* Use last used antenna */
-
-void b43_generate_txhdr(struct b43_wldev *dev,
-			u8 * txhdr,
-			const unsigned char *fragment_data,
-			unsigned int fragment_len,
-			const struct ieee80211_tx_control *txctl, u16 cookie);
+#define B43_TXH_PHY_ENC			0x0003 /* Data frame encoding */
+#define  B43_TXH_PHY_ENC_CCK		0x0000 /* CCK */
+#define  B43_TXH_PHY_ENC_OFDM		0x0001 /* OFDM */
+#define  B43_TXH_PHY_ENC_EWC		0x0002 /* EWC */
+#define  B43_TXH_PHY_ENC_N		0x0003 /* N */
+#define B43_TXH_PHY_SHORTPRMBL		0x0010 /* Use short preamble */
+#define B43_TXH_PHY_ANT			0x03C0 /* Antenna selection */
+#define  B43_TXH_PHY_ANT0		0x0000 /* Use antenna 0 */
+#define  B43_TXH_PHY_ANT1		0x0040 /* Use antenna 1 */
+#define  B43_TXH_PHY_ANT01AUTO		0x00C0 /* Use antenna 0/1 auto */
+#define  B43_TXH_PHY_ANT2		0x0100 /* Use antenna 2 */
+#define  B43_TXH_PHY_ANT3		0x0200 /* Use antenna 3 */
+#define B43_TXH_PHY_TXPWR		0xFC00 /* TX power */
+#define B43_TXH_PHY_TXPWR_SHIFT		10
+
+/* PHY TX control word 1 */
+#define B43_TXH_PHY1_BW			0x0007 /* Bandwidth */
+#define  B43_TXH_PHY1_BW_10		0x0000 /* 10 MHz */
+#define  B43_TXH_PHY1_BW_10U		0x0001 /* 10 MHz upper */
+#define  B43_TXH_PHY1_BW_20		0x0002 /* 20 MHz */
+#define  B43_TXH_PHY1_BW_20U		0x0003 /* 20 MHz upper */
+#define  B43_TXH_PHY1_BW_40		0x0004 /* 40 MHz */
+#define  B43_TXH_PHY1_BW_40DUP		0x0005 /* 50 MHz duplicate */
+#define B43_TXH_PHY1_MODE		0x0038 /* Mode */
+#define  B43_TXH_PHY1_MODE_SISO		0x0000 /* SISO */
+#define  B43_TXH_PHY1_MODE_CDD		0x0008 /* CDD */
+#define  B43_TXH_PHY1_MODE_STBC		0x0010 /* STBC */
+#define  B43_TXH_PHY1_MODE_SDM		0x0018 /* SDM */
+#define B43_TXH_PHY1_CRATE		0x0700 /* Coding rate */
+#define  B43_TXH_PHY1_CRATE_1_2		0x0000 /* 1/2 */
+#define  B43_TXH_PHY1_CRATE_2_3		0x0100 /* 2/3 */
+#define  B43_TXH_PHY1_CRATE_3_4		0x0200 /* 3/4 */
+#define  B43_TXH_PHY1_CRATE_4_5		0x0300 /* 4/5 */
+#define  B43_TXH_PHY1_CRATE_5_6		0x0400 /* 5/6 */
+#define  B43_TXH_PHY1_CRATE_7_8		0x0600 /* 7/8 */
+#define B43_TXH_PHY1_MODUL		0x3800 /* Modulation scheme */
+#define  B43_TXH_PHY1_MODUL_BPSK	0x0000 /* BPSK */
+#define  B43_TXH_PHY1_MODUL_QPSK	0x0800 /* QPSK */
+#define  B43_TXH_PHY1_MODUL_QAM16	0x1000 /* QAM16 */
+#define  B43_TXH_PHY1_MODUL_QAM64	0x1800 /* QAM64 */
+#define  B43_TXH_PHY1_MODUL_QAM256	0x2000 /* QAM256 */
+
+
+/* r351 firmware compatibility stuff. */
+static inline
+bool b43_is_old_txhdr_format(struct b43_wldev *dev)
+{
+	return (dev->fw.rev <= 351);
+}
+
+static inline
+size_t b43_txhdr_size(struct b43_wldev *dev)
+{
+	if (b43_is_old_txhdr_format(dev))
+		return 100 + sizeof(struct b43_plcp_hdr6);
+	return 104 + sizeof(struct b43_plcp_hdr6);
+}
+
+
+int b43_generate_txhdr(struct b43_wldev *dev,
+		       u8 * txhdr,
+		       const unsigned char *fragment_data,
+		       unsigned int fragment_len,
+		       const struct ieee80211_tx_control *txctl, u16 cookie);
 
 /* Transmit Status */
 struct b43_txstatus {
@@ -142,49 +234,56 @@ struct b43_rxhdr_fw4 {
 } __attribute__ ((__packed__));
 
 /* PHY RX Status 0 */
-#define B43_RX_PHYST0_GAINCTL	0x4000	/* Gain Control */
-#define B43_RX_PHYST0_PLCPHCF	0x0200
-#define B43_RX_PHYST0_PLCPFV	0x0100
-#define B43_RX_PHYST0_SHORTPRMBL	0x0080	/* Received with Short Preamble */
+#define B43_RX_PHYST0_GAINCTL		0x4000 /* Gain Control */
+#define B43_RX_PHYST0_PLCPHCF		0x0200
+#define B43_RX_PHYST0_PLCPFV		0x0100
+#define B43_RX_PHYST0_SHORTPRMBL	0x0080 /* Received with Short Preamble */
 #define B43_RX_PHYST0_LCRS		0x0040
-#define B43_RX_PHYST0_ANT		0x0020	/* Antenna */
-#define B43_RX_PHYST0_UNSRATE	0x0010
+#define B43_RX_PHYST0_ANT		0x0020 /* Antenna */
+#define B43_RX_PHYST0_UNSRATE		0x0010
 #define B43_RX_PHYST0_CLIP		0x000C
 #define B43_RX_PHYST0_CLIP_SHIFT	2
-#define B43_RX_PHYST0_FTYPE		0x0003	/* Frame type */
-#define  B43_RX_PHYST0_CCK		0x0000	/* Frame type: CCK */
-#define  B43_RX_PHYST0_OFDM		0x0001	/* Frame type: OFDM */
-#define  B43_RX_PHYST0_PRE_N	0x0002	/* Pre-standard N-PHY frame */
-#define  B43_RX_PHYST0_STD_N	0x0003	/* Standard N-PHY frame */
+#define B43_RX_PHYST0_FTYPE		0x0003 /* Frame type */
+#define  B43_RX_PHYST0_CCK		0x0000 /* Frame type: CCK */
+#define  B43_RX_PHYST0_OFDM		0x0001 /* Frame type: OFDM */
+#define  B43_RX_PHYST0_PRE_N		0x0002 /* Pre-standard N-PHY frame */
+#define  B43_RX_PHYST0_STD_N		0x0003 /* Standard N-PHY frame */
 
 /* PHY RX Status 2 */
-#define B43_RX_PHYST2_LNAG		0xC000	/* LNA Gain */
+#define B43_RX_PHYST2_LNAG		0xC000 /* LNA Gain */
 #define B43_RX_PHYST2_LNAG_SHIFT	14
-#define B43_RX_PHYST2_PNAG		0x3C00	/* PNA Gain */
+#define B43_RX_PHYST2_PNAG		0x3C00 /* PNA Gain */
 #define B43_RX_PHYST2_PNAG_SHIFT	10
-#define B43_RX_PHYST2_FOFF		0x03FF	/* F offset */
+#define B43_RX_PHYST2_FOFF		0x03FF /* F offset */
 
 /* PHY RX Status 3 */
-#define B43_RX_PHYST3_DIGG		0x1800	/* DIG Gain */
+#define B43_RX_PHYST3_DIGG		0x1800 /* DIG Gain */
 #define B43_RX_PHYST3_DIGG_SHIFT	11
-#define B43_RX_PHYST3_TRSTATE	0x0400	/* TR state */
+#define B43_RX_PHYST3_TRSTATE		0x0400 /* TR state */
 
 /* MAC RX Status */
-#define B43_RX_MAC_BEACONSENT	0x00008000	/* Beacon send flag */
-#define B43_RX_MAC_KEYIDX		0x000007E0	/* Key index */
-#define B43_RX_MAC_KEYIDX_SHIFT	5
-#define B43_RX_MAC_DECERR		0x00000010	/* Decrypt error */
-#define B43_RX_MAC_DEC		0x00000008	/* Decryption attempted */
-#define B43_RX_MAC_PADDING		0x00000004	/* Pad bytes present */
-#define B43_RX_MAC_RESP		0x00000002	/* Response frame transmitted */
-#define B43_RX_MAC_FCSERR		0x00000001	/* FCS error */
+#define B43_RX_MAC_RXST_VALID		0x01000000 /* PHY RXST valid */
+#define B43_RX_MAC_TKIP_MICERR		0x00100000 /* TKIP MIC error */
+#define B43_RX_MAC_TKIP_MICATT		0x00080000 /* TKIP MIC attempted */
+#define B43_RX_MAC_AGGTYPE		0x00060000 /* Aggregation type */
+#define B43_RX_MAC_AGGTYPE_SHIFT	17
+#define B43_RX_MAC_AMSDU		0x00010000 /* A-MSDU mask */
+#define B43_RX_MAC_BEACONSENT		0x00008000 /* Beacon sent flag */
+#define B43_RX_MAC_KEYIDX		0x000007E0 /* Key index */
+#define B43_RX_MAC_KEYIDX_SHIFT		5
+#define B43_RX_MAC_DECERR		0x00000010 /* Decrypt error */
+#define B43_RX_MAC_DEC			0x00000008 /* Decryption attempted */
+#define B43_RX_MAC_PADDING		0x00000004 /* Pad bytes present */
+#define B43_RX_MAC_RESP			0x00000002 /* Response frame transmitted */
+#define B43_RX_MAC_FCSERR		0x00000001 /* FCS error */
 
 /* RX channel */
-#define B43_RX_CHAN_GAIN		0xFC00	/* Gain */
-#define B43_RX_CHAN_GAIN_SHIFT	10
-#define B43_RX_CHAN_ID		0x03FC	/* Channel ID */
-#define B43_RX_CHAN_ID_SHIFT	2
-#define B43_RX_CHAN_PHYTYPE		0x0003	/* PHY type */
+#define B43_RX_CHAN_40MHZ		0x1000 /* 40 Mhz channel width */
+#define B43_RX_CHAN_5GHZ		0x0800 /* 5 Ghz band */
+#define B43_RX_CHAN_ID			0x07F8 /* Channel ID */
+#define B43_RX_CHAN_ID_SHIFT		3
+#define B43_RX_CHAN_PHYTYPE		0x0007 /* PHY type */
+
 
 u8 b43_plcp_get_ratecode_cck(const u8 bitrate);
 u8 b43_plcp_get_ratecode_ofdm(const u8 bitrate);
diff --git a/package/hostapd/files/default.config b/package/hostapd/files/default.config
index 700217dada..f383e116cd 100644
--- a/package/hostapd/files/default.config
+++ b/package/hostapd/files/default.config
@@ -23,7 +23,7 @@ CONFIG_DRIVER_MADWIFI=y
 #CONFIG_DRIVER_PRISM54=y
 
 # Driver interface for drivers using Devicescape IEEE 802.11 stack
-CONFIG_DRIVER_DEVICESCAPE=y
+#CONFIG_DRIVER_DEVICESCAPE=y
 # Currently, driver_devicescape.c build requires some additional parameters
 # to be able to include some of the kernel header files. Following lines can
 # be used to set these (WIRELESS_DEV must point to the root directory of the
diff --git a/package/hostapd/files/mini.config b/package/hostapd/files/mini.config
index a2f3f62bba..d1ab057ccc 100644
--- a/package/hostapd/files/mini.config
+++ b/package/hostapd/files/mini.config
@@ -23,7 +23,7 @@ CONFIG_DRIVER_MADWIFI=y
 #CONFIG_DRIVER_PRISM54=y
 
 # Driver interface for drivers using Devicescape IEEE 802.11 stack
-CONFIG_DRIVER_DEVICESCAPE=y
+#CONFIG_DRIVER_DEVICESCAPE=y
 # Currently, driver_devicescape.c build requires some additional parameters
 # to be able to include some of the kernel header files. Following lines can
 # be used to set these (WIRELESS_DEV must point to the root directory of the
diff --git a/package/mac80211/Makefile b/package/mac80211/Makefile
index 723ba77be5..9d8320e180 100644
--- a/package/mac80211/Makefile
+++ b/package/mac80211/Makefile
@@ -28,11 +28,12 @@ define KernelPackage/mac80211/description
 Linux 802.11 Wireless Networking Stack
 endef
 
-CONFOPTS:=MAC80211 CFG80211 NL80211
+CONFOPTS:=MAC80211 CFG80211 NL80211 MAC80211_RC_DEFAULT_PID MAC80211_RC_PID
 
 BUILDFLAGS:= \
-	$(foreach opt,$(CONFOPTS),-DCONFIG_$(opt) -DCONFIG_MAC80211_RCSIMPLE=1) \
-	$(if $(CONFIG_LEDS_TRIGGERS), -DCONFIG_MAC80211_LEDS -DCONFIG_LEDS_TRIGGERS)
+	$(foreach opt,$(CONFOPTS),-DCONFIG_$(opt)) \
+	$(if $(CONFIG_LEDS_TRIGGERS), -DCONFIG_MAC80211_LEDS -DCONFIG_LEDS_TRIGGERS) \
+	-D__CONFIG_MAC80211_RC_DEFAULT=pid
 
 MAKE_OPTS:= \
 	CROSS_COMPILE="$(TARGET_CROSS)" \
@@ -40,7 +41,7 @@ MAKE_OPTS:= \
 	EXTRA_CFLAGS="$(BUILDFLAGS)" \
 	$(foreach opt,$(CONFOPTS),CONFIG_$(opt)=m) \
 	CONFIG_NL80211=y \
-	CONFIG_MAC80211_RCSIMPLE=y \
+	CONFIG_MAC80211_RC_PID=y \
 	CONFIG_MAC80211_LEDS=$(CONFIG_LEDS_TRIGGERS) \
 	LINUXINCLUDE="-I$(PKG_BUILD_DIR)/include -I$(LINUX_DIR)/include -include linux/autoconf.h" \
 
diff --git a/package/mac80211/patches/000-mac80211_update.patch b/package/mac80211/patches/000-mac80211_update.patch
deleted file mode 100644
index 7a1a1e271b..0000000000
--- a/package/mac80211/patches/000-mac80211_update.patch
+++ /dev/null
@@ -1,933 +0,0 @@
-Index: mac80211/include/linux/ieee80211.h
-===================================================================
---- mac80211.orig/include/linux/ieee80211.h	2007-11-11 15:45:23.153490050 +0100
-+++ mac80211/include/linux/ieee80211.h	2007-11-11 15:45:30.417904025 +0100
-@@ -81,18 +81,18 @@
- 
- 
- /* miscellaneous IEEE 802.11 constants */
--#define IEEE80211_MAX_FRAG_THRESHOLD	2346
--#define IEEE80211_MAX_RTS_THRESHOLD	2347
-+#define IEEE80211_MAX_FRAG_THRESHOLD	2352
-+#define IEEE80211_MAX_RTS_THRESHOLD	2353
- #define IEEE80211_MAX_AID		2007
- #define IEEE80211_MAX_TIM_LEN		251
--#define IEEE80211_MAX_DATA_LEN		2304
- /* Maximum size for the MA-UNITDATA primitive, 802.11 standard section
-    6.2.1.1.2.
- 
--   The figure in section 7.1.2 suggests a body size of up to 2312
--   bytes is allowed, which is a bit confusing, I suspect this
--   represents the 2304 bytes of real data, plus a possible 8 bytes of
--   WEP IV and ICV. (this interpretation suggested by Ramiro Barreiro) */
-+   802.11e clarifies the figure in section 7.1.2. The frame body is
-+   up to 2304 octets long (maximum MSDU size) plus any crypt overhead. */
-+#define IEEE80211_MAX_DATA_LEN		2304
-+/* 30 byte 4 addr hdr, 2 byte QoS, 2304 byte MSDU, 12 byte crypt, 4 byte FCS */
-+#define IEEE80211_MAX_FRAME_LEN		2352
- 
- #define IEEE80211_MAX_SSID_LEN		32
- 
-Index: mac80211/include/linux/nl80211.h
-===================================================================
---- mac80211.orig/include/linux/nl80211.h	2007-11-11 15:45:23.161490506 +0100
-+++ mac80211/include/linux/nl80211.h	2007-11-11 15:45:30.421904255 +0100
-@@ -25,7 +25,7 @@
-  *	either a dump request on a %NL80211_ATTR_WIPHY or a specific get
-  *	on an %NL80211_ATTR_IFINDEX is supported.
-  * @NL80211_CMD_SET_INTERFACE: Set type of a virtual interface, requires
-- 	%NL80211_ATTR_IFINDEX and %NL80211_ATTR_IFTYPE.
-+ *	%NL80211_ATTR_IFINDEX and %NL80211_ATTR_IFTYPE.
-  * @NL80211_CMD_NEW_INTERFACE: Newly created virtual interface or response
-  *	to %NL80211_CMD_GET_INTERFACE. Has %NL80211_ATTR_IFINDEX,
-  *	%NL80211_ATTR_WIPHY and %NL80211_ATTR_IFTYPE attributes. Can also
-Index: mac80211/include/net/mac80211.h
-===================================================================
---- mac80211.orig/include/net/mac80211.h	2007-11-11 15:45:23.169490961 +0100
-+++ mac80211/include/net/mac80211.h	2007-11-11 15:45:30.429904707 +0100
-@@ -706,11 +706,16 @@
-  *
-  * @queues: number of available hardware transmit queues for
-  *	data packets. WMM/QoS requires at least four.
-+ *
-+ * @rate_control_algorithm: rate control algorithm for this hardware.
-+ *	If unset (NULL), the default algorithm will be used. Must be
-+ *	set before calling ieee80211_register_hw().
-  */
- struct ieee80211_hw {
- 	struct ieee80211_conf conf;
- 	struct wiphy *wiphy;
- 	struct workqueue_struct *workqueue;
-+	const char *rate_control_algorithm;
- 	void *priv;
- 	u32 flags;
- 	unsigned int extra_tx_headroom;
-@@ -936,27 +941,11 @@
-  *	and remove_interface calls, i.e. while the interface with the
-  *	given local_address is enabled.
-  *
-- * @set_ieee8021x: Enable/disable IEEE 802.1X. This item requests wlan card
-- *	to pass unencrypted EAPOL-Key frames even when encryption is
-- *	configured. If the wlan card does not require such a configuration,
-- *	this function pointer can be set to NULL.
-- *
-- * @set_port_auth: Set port authorization state (IEEE 802.1X PAE) to be
-- *	authorized (@authorized=1) or unauthorized (=0). This function can be
-- *	used if the wlan hardware or low-level driver implements PAE.
-- *	mac80211 will filter frames based on authorization state in any case,
-- *	so this function pointer can be NULL if low-level driver does not
-- *	require event notification about port state changes.
-- *
-  * @hw_scan: Ask the hardware to service the scan request, no need to start
-  *	the scan state machine in stack.
-  *
-  * @get_stats: return low-level statistics
-  *
-- * @set_privacy_invoked: For devices that generate their own beacons and probe
-- *	response or association responses this updates the state of privacy_invoked
-- *	returns 0 for success or an error number.
-- *
-  * @get_sequence_counter: For devices that have internal sequence counters this
-  *	callback allows mac80211 to access the current value of a counter.
-  *	This callback seems not well-defined, tell us if you need it.
-@@ -1029,14 +1018,9 @@
- 	int (*set_key)(struct ieee80211_hw *hw, enum set_key_cmd cmd,
- 		       const u8 *local_address, const u8 *address,
- 		       struct ieee80211_key_conf *key);
--	int (*set_ieee8021x)(struct ieee80211_hw *hw, int use_ieee8021x);
--	int (*set_port_auth)(struct ieee80211_hw *hw, u8 *addr,
--			     int authorized);
- 	int (*hw_scan)(struct ieee80211_hw *hw, u8 *ssid, size_t len);
- 	int (*get_stats)(struct ieee80211_hw *hw,
- 			 struct ieee80211_low_level_stats *stats);
--	int (*set_privacy_invoked)(struct ieee80211_hw *hw,
--				   int privacy_invoked);
- 	int (*get_sequence_counter)(struct ieee80211_hw *hw,
- 				    u8* addr, u8 keyidx, u8 txrx,
- 				    u32* iv32, u16* iv16);
-Index: mac80211/net/mac80211/aes_ccm.c
-===================================================================
---- mac80211.orig/net/mac80211/aes_ccm.c	2007-11-11 15:45:23.177491419 +0100
-+++ mac80211/net/mac80211/aes_ccm.c	2007-11-11 15:45:30.433904936 +0100
-@@ -7,10 +7,10 @@
-  * published by the Free Software Foundation.
-  */
- 
-+#include <linux/kernel.h>
- #include <linux/types.h>
- #include <linux/crypto.h>
- #include <linux/err.h>
--#include <asm/scatterlist.h>
- 
- #include <net/mac80211.h>
- #include "ieee80211_key.h"
-@@ -63,7 +63,7 @@
- 	s_0 = scratch + AES_BLOCK_LEN;
- 	e = scratch + 2 * AES_BLOCK_LEN;
- 
--	num_blocks = (data_len + AES_BLOCK_LEN - 1) / AES_BLOCK_LEN;
-+	num_blocks = DIV_ROUND_UP(data_len, AES_BLOCK_LEN);
- 	last_len = data_len % AES_BLOCK_LEN;
- 	aes_ccm_prepare(tfm, b_0, aad, b, s_0, b);
- 
-@@ -102,7 +102,7 @@
- 	s_0 = scratch + AES_BLOCK_LEN;
- 	a = scratch + 2 * AES_BLOCK_LEN;
- 
--	num_blocks = (data_len + AES_BLOCK_LEN - 1) / AES_BLOCK_LEN;
-+	num_blocks = DIV_ROUND_UP(data_len, AES_BLOCK_LEN);
- 	last_len = data_len % AES_BLOCK_LEN;
- 	aes_ccm_prepare(tfm, b_0, aad, b, s_0, a);
- 
-Index: mac80211/net/mac80211/ieee80211.c
-===================================================================
---- mac80211.orig/net/mac80211/ieee80211.c	2007-11-11 15:45:23.185491871 +0100
-+++ mac80211/net/mac80211/ieee80211.c	2007-11-11 15:45:30.437905164 +0100
-@@ -1061,7 +1061,8 @@
- 	ieee80211_debugfs_add_netdev(IEEE80211_DEV_TO_SUB_IF(local->mdev));
- 	ieee80211_if_set_type(local->mdev, IEEE80211_IF_TYPE_AP);
- 
--	result = ieee80211_init_rate_ctrl_alg(local, NULL);
-+	result = ieee80211_init_rate_ctrl_alg(local,
-+					      hw->rate_control_algorithm);
- 	if (result < 0) {
- 		printk(KERN_DEBUG "%s: Failed to initialize rate control "
- 		       "algorithm\n", wiphy_name(local->hw.wiphy));
-@@ -1222,8 +1223,17 @@
- 
- 	BUILD_BUG_ON(sizeof(struct ieee80211_tx_packet_data) > sizeof(skb->cb));
- 
-+#ifdef CONFIG_MAC80211_RCSIMPLE
-+	ret = ieee80211_rate_control_register(&mac80211_rcsimple);
-+	if (ret)
-+		return ret;
-+#endif
-+
- 	ret = ieee80211_wme_register();
- 	if (ret) {
-+#ifdef CONFIG_MAC80211_RCSIMPLE
-+		ieee80211_rate_control_unregister(&mac80211_rcsimple);
-+#endif
- 		printk(KERN_DEBUG "ieee80211_init: failed to "
- 		       "initialize WME (err=%d)\n", ret);
- 		return ret;
-@@ -1237,6 +1247,10 @@
- 
- static void __exit ieee80211_exit(void)
- {
-+#ifdef CONFIG_MAC80211_RCSIMPLE
-+	ieee80211_rate_control_unregister(&mac80211_rcsimple);
-+#endif
-+
- 	ieee80211_wme_unregister();
- 	ieee80211_debugfs_netdev_exit();
- }
-Index: mac80211/net/mac80211/ieee80211_i.h
-===================================================================
---- mac80211.orig/net/mac80211/ieee80211_i.h	2007-11-11 15:45:23.189492100 +0100
-+++ mac80211/net/mac80211/ieee80211_i.h	2007-11-11 15:45:30.441905395 +0100
-@@ -232,6 +232,7 @@
- #define IEEE80211_STA_AUTO_SSID_SEL	BIT(10)
- #define IEEE80211_STA_AUTO_BSSID_SEL	BIT(11)
- #define IEEE80211_STA_AUTO_CHANNEL_SEL	BIT(12)
-+#define IEEE80211_STA_PRIVACY_INVOKED	BIT(13)
- struct ieee80211_if_sta {
- 	enum {
- 		IEEE80211_DISABLED, IEEE80211_AUTHENTICATE,
-@@ -261,7 +262,6 @@
- 	unsigned long request;
- 	struct sk_buff_head skb_queue;
- 
--	int key_management_enabled;
- 	unsigned long last_probe;
- 
- #define IEEE80211_AUTH_ALG_OPEN BIT(0)
-Index: mac80211/net/mac80211/ieee80211_ioctl.c
-===================================================================
---- mac80211.orig/net/mac80211/ieee80211_ioctl.c	2007-11-11 15:45:23.197492559 +0100
-+++ mac80211/net/mac80211/ieee80211_ioctl.c	2007-11-11 15:45:30.441905395 +0100
-@@ -305,9 +305,12 @@
- 			    ((chan->chan == channel) || (chan->freq == freq))) {
- 				local->oper_channel = chan;
- 				local->oper_hw_mode = mode;
--				set++;
-+				set = 1;
-+				break;
- 			}
- 		}
-+		if (set)
-+			break;
- 	}
- 
- 	if (set) {
-@@ -507,10 +510,11 @@
- 
- static int ieee80211_ioctl_siwscan(struct net_device *dev,
- 				   struct iw_request_info *info,
--				   struct iw_point *data, char *extra)
-+				   union iwreq_data *wrqu, char *extra)
- {
- 	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
- 	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-+	struct iw_scan_req *req = NULL;
- 	u8 *ssid = NULL;
- 	size_t ssid_len = 0;
- 
-@@ -535,6 +539,14 @@
- 		return -EOPNOTSUPP;
- 	}
- 
-+	/* if SSID was specified explicitly then use that */
-+	if (wrqu->data.length == sizeof(struct iw_scan_req) &&
-+	    wrqu->data.flags & IW_SCAN_THIS_ESSID) {
-+		req = (struct iw_scan_req *)extra;
-+		ssid = req->essid;
-+		ssid_len = req->essid_len;
-+	}
-+
- 	return ieee80211_sta_req_scan(dev, ssid, ssid_len);
- }
- 
-@@ -621,22 +633,35 @@
- {
- 	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
- 	bool need_reconfig = 0;
-+	u8 new_power_level;
- 
- 	if ((data->txpower.flags & IW_TXPOW_TYPE) != IW_TXPOW_DBM)
- 		return -EINVAL;
- 	if (data->txpower.flags & IW_TXPOW_RANGE)
- 		return -EINVAL;
--	if (!data->txpower.fixed)
--		return -EINVAL;
- 
--	if (local->hw.conf.power_level != data->txpower.value) {
--		local->hw.conf.power_level = data->txpower.value;
-+	if (data->txpower.fixed) {
-+		new_power_level = data->txpower.value;
-+	} else {
-+		/* Automatic power level. Get the px power from the current
-+		 * channel. */
-+		struct ieee80211_channel* chan = local->oper_channel;
-+		if (!chan)
-+			return -EINVAL;
-+
-+		new_power_level = chan->power_level;
-+	}
-+
-+	if (local->hw.conf.power_level != new_power_level) {
-+		local->hw.conf.power_level = new_power_level;
- 		need_reconfig = 1;
- 	}
-+
- 	if (local->hw.conf.radio_enabled != !(data->txpower.disabled)) {
- 		local->hw.conf.radio_enabled = !(data->txpower.disabled);
- 		need_reconfig = 1;
- 	}
-+
- 	if (need_reconfig) {
- 		ieee80211_hw_config(local);
- 		/* The return value of hw_config is not of big interest here,
-@@ -904,7 +929,6 @@
- 				   struct iw_request_info *info,
- 				   struct iw_param *data, char *extra)
- {
--	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
- 	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
- 	int ret = 0;
- 
-@@ -914,18 +938,21 @@
- 	case IW_AUTH_CIPHER_GROUP:
- 	case IW_AUTH_WPA_ENABLED:
- 	case IW_AUTH_RX_UNENCRYPTED_EAPOL:
--		break;
- 	case IW_AUTH_KEY_MGMT:
-+		break;
-+	case IW_AUTH_PRIVACY_INVOKED:
- 		if (sdata->type != IEEE80211_IF_TYPE_STA)
- 			ret = -EINVAL;
- 		else {
-+			sdata->u.sta.flags &= ~IEEE80211_STA_PRIVACY_INVOKED;
- 			/*
--			 * Key management was set by wpa_supplicant,
--			 * we only need this to associate to a network
--			 * that has privacy enabled regardless of not
--			 * having a key.
-+			 * Privacy invoked by wpa_supplicant, store the
-+			 * value and allow associating to a protected
-+			 * network without having a key up front.
- 			 */
--			sdata->u.sta.key_management_enabled = !!data->value;
-+			if (data->value)
-+				sdata->u.sta.flags |=
-+					IEEE80211_STA_PRIVACY_INVOKED;
- 		}
- 		break;
- 	case IW_AUTH_80211_AUTH_ALG:
-@@ -935,11 +962,6 @@
- 		else
- 			ret = -EOPNOTSUPP;
- 		break;
--	case IW_AUTH_PRIVACY_INVOKED:
--		if (local->ops->set_privacy_invoked)
--			ret = local->ops->set_privacy_invoked(
--					local_to_hw(local), data->value);
--		break;
- 	default:
- 		ret = -EOPNOTSUPP;
- 		break;
-Index: mac80211/net/mac80211/ieee80211_rate.c
-===================================================================
---- mac80211.orig/net/mac80211/ieee80211_rate.c	2007-11-11 15:45:23.205493011 +0100
-+++ mac80211/net/mac80211/ieee80211_rate.c	2007-11-11 15:45:30.441905395 +0100
-@@ -25,13 +25,25 @@
- {
- 	struct rate_control_alg *alg;
- 
-+	if (!ops->name)
-+		return -EINVAL;
-+
-+	mutex_lock(&rate_ctrl_mutex);
-+	list_for_each_entry(alg, &rate_ctrl_algs, list) {
-+		if (!strcmp(alg->ops->name, ops->name)) {
-+			/* don't register an algorithm twice */
-+			WARN_ON(1);
-+			return -EALREADY;
-+		}
-+	}
-+
- 	alg = kzalloc(sizeof(*alg), GFP_KERNEL);
- 	if (alg == NULL) {
-+		mutex_unlock(&rate_ctrl_mutex);
- 		return -ENOMEM;
- 	}
- 	alg->ops = ops;
- 
--	mutex_lock(&rate_ctrl_mutex);
- 	list_add_tail(&alg->list, &rate_ctrl_algs);
- 	mutex_unlock(&rate_ctrl_mutex);
- 
-@@ -61,9 +73,12 @@
- 	struct rate_control_alg *alg;
- 	struct rate_control_ops *ops = NULL;
- 
-+	if (!name)
-+		return NULL;
-+
- 	mutex_lock(&rate_ctrl_mutex);
- 	list_for_each_entry(alg, &rate_ctrl_algs, list) {
--		if (!name || !strcmp(alg->ops->name, name))
-+		if (!strcmp(alg->ops->name, name))
- 			if (try_module_get(alg->ops->module)) {
- 				ops = alg->ops;
- 				break;
-@@ -80,9 +95,12 @@
- {
- 	struct rate_control_ops *ops;
- 
-+	if (!name)
-+		name = "simple";
-+
- 	ops = ieee80211_try_rate_control_ops_get(name);
- 	if (!ops) {
--		request_module("rc80211_%s", name ? name : "default");
-+		request_module("rc80211_%s", name);
- 		ops = ieee80211_try_rate_control_ops_get(name);
- 	}
- 	return ops;
-Index: mac80211/net/mac80211/ieee80211_rate.h
-===================================================================
---- mac80211.orig/net/mac80211/ieee80211_rate.h	2007-11-11 15:45:23.213493469 +0100
-+++ mac80211/net/mac80211/ieee80211_rate.h	2007-11-11 15:45:30.445905621 +0100
-@@ -65,6 +65,9 @@
- 	struct kref kref;
- };
- 
-+/* default 'simple' algorithm */
-+extern struct rate_control_ops mac80211_rcsimple;
-+
- int ieee80211_rate_control_register(struct rate_control_ops *ops);
- void ieee80211_rate_control_unregister(struct rate_control_ops *ops);
- 
-Index: mac80211/net/mac80211/ieee80211_sta.c
-===================================================================
---- mac80211.orig/net/mac80211/ieee80211_sta.c	2007-11-11 15:45:23.217493699 +0100
-+++ mac80211/net/mac80211/ieee80211_sta.c	2007-11-11 15:46:32.885463850 +0100
-@@ -12,7 +12,6 @@
-  */
- 
- /* TODO:
-- * BSS table: use <BSSID,SSID> as the key to support multi-SSID APs
-  * order BSS list by RSSI(?) ("quality of AP")
-  * scan result table filtering (by capability (privacy, IBSS/BSS, WPA/RSN IE,
-  *    SSID)
-@@ -61,7 +60,8 @@
- static void ieee80211_send_probe_req(struct net_device *dev, u8 *dst,
- 				     u8 *ssid, size_t ssid_len);
- static struct ieee80211_sta_bss *
--ieee80211_rx_bss_get(struct net_device *dev, u8 *bssid);
-+ieee80211_rx_bss_get(struct net_device *dev, u8 *bssid, int channel,
-+		     u8 *ssid, u8 ssid_len);
- static void ieee80211_rx_bss_put(struct net_device *dev,
- 				 struct ieee80211_sta_bss *bss);
- static int ieee80211_sta_find_ibss(struct net_device *dev,
-@@ -108,14 +108,11 @@
- 	u8 wmm_param_len;
- };
- 
--enum ParseRes { ParseOK = 0, ParseUnknown = 1, ParseFailed = -1 };
--
--static enum ParseRes ieee802_11_parse_elems(u8 *start, size_t len,
--					    struct ieee802_11_elems *elems)
-+static void ieee802_11_parse_elems(u8 *start, size_t len,
-+				   struct ieee802_11_elems *elems)
- {
- 	size_t left = len;
- 	u8 *pos = start;
--	int unknown = 0;
- 
- 	memset(elems, 0, sizeof(*elems));
- 
-@@ -126,15 +123,8 @@
- 		elen = *pos++;
- 		left -= 2;
- 
--		if (elen > left) {
--#if 0
--			if (net_ratelimit())
--				printk(KERN_DEBUG "IEEE 802.11 element parse "
--				       "failed (id=%d elen=%d left=%d)\n",
--				       id, elen, left);
--#endif
--			return ParseFailed;
--		}
-+		if (elen > left)
-+			return;
- 
- 		switch (id) {
- 		case WLAN_EID_SSID:
-@@ -201,28 +191,15 @@
- 			elems->ext_supp_rates_len = elen;
- 			break;
- 		default:
--#if 0
--			printk(KERN_DEBUG "IEEE 802.11 element parse ignored "
--				      "unknown element (id=%d elen=%d)\n",
--				      id, elen);
--#endif
--			unknown++;
- 			break;
- 		}
- 
- 		left -= elen;
- 		pos += elen;
- 	}
--
--	/* Do not trigger error if left == 1 as Apple Airport base stations
--	 * send AssocResps that are one spurious byte too long. */
--
--	return unknown ? ParseUnknown : ParseOK;
- }
- 
- 
--
--
- static int ecw2cw(int ecw)
- {
- 	int cw = 1;
-@@ -426,7 +403,9 @@
- 		if (sdata->type != IEEE80211_IF_TYPE_STA)
- 			return;
- 
--		bss = ieee80211_rx_bss_get(dev, ifsta->bssid);
-+		bss = ieee80211_rx_bss_get(dev, ifsta->bssid,
-+					   local->hw.conf.channel,
-+					   ifsta->ssid, ifsta->ssid_len);
- 		if (bss) {
- 			if (bss->has_erp_value)
- 				ieee80211_handle_erp_ie(dev, bss->erp_value);
-@@ -571,7 +550,8 @@
- 		capab |= WLAN_CAPABILITY_SHORT_SLOT_TIME |
- 			WLAN_CAPABILITY_SHORT_PREAMBLE;
- 	}
--	bss = ieee80211_rx_bss_get(dev, ifsta->bssid);
-+	bss = ieee80211_rx_bss_get(dev, ifsta->bssid, local->hw.conf.channel,
-+				   ifsta->ssid, ifsta->ssid_len);
- 	if (bss) {
- 		if (bss->capability & WLAN_CAPABILITY_PRIVACY)
- 			capab |= WLAN_CAPABILITY_PRIVACY;
-@@ -719,24 +699,30 @@
- static int ieee80211_privacy_mismatch(struct net_device *dev,
- 				      struct ieee80211_if_sta *ifsta)
- {
-+	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
- 	struct ieee80211_sta_bss *bss;
--	int res = 0;
-+	int bss_privacy;
-+	int wep_privacy;
-+	int privacy_invoked;
- 
--	if (!ifsta || (ifsta->flags & IEEE80211_STA_MIXED_CELL) ||
--	    ifsta->key_management_enabled)
-+	if (!ifsta || (ifsta->flags & IEEE80211_STA_MIXED_CELL))
- 		return 0;
- 
--	bss = ieee80211_rx_bss_get(dev, ifsta->bssid);
-+	bss = ieee80211_rx_bss_get(dev, ifsta->bssid, local->hw.conf.channel,
-+				   ifsta->ssid, ifsta->ssid_len);
- 	if (!bss)
- 		return 0;
- 
--	if (ieee80211_sta_wep_configured(dev) !=
--	    !!(bss->capability & WLAN_CAPABILITY_PRIVACY))
--		res = 1;
-+	bss_privacy = !!(bss->capability & WLAN_CAPABILITY_PRIVACY);
-+	wep_privacy = !!ieee80211_sta_wep_configured(dev);
-+	privacy_invoked = !!(ifsta->flags & IEEE80211_STA_PRIVACY_INVOKED);
- 
- 	ieee80211_rx_bss_put(dev, bss);
- 
--	return res;
-+	if ((bss_privacy == wep_privacy) || (bss_privacy == privacy_invoked))
-+		return 0;
-+
-+	return 1;
- }
- 
- 
-@@ -920,12 +906,7 @@
- 
- 	printk(KERN_DEBUG "%s: replying to auth challenge\n", dev->name);
- 	pos = mgmt->u.auth.variable;
--	if (ieee802_11_parse_elems(pos, len - (pos - (u8 *) mgmt), &elems)
--	    == ParseFailed) {
--		printk(KERN_DEBUG "%s: failed to parse Auth(challenge)\n",
--		       dev->name);
--		return;
--	}
-+	ieee802_11_parse_elems(pos, len - (pos - (u8 *) mgmt), &elems);
- 	if (!elems.challenge) {
- 		printk(KERN_DEBUG "%s: no challenge IE in shared key auth "
- 		       "frame\n", dev->name);
-@@ -1214,12 +1195,7 @@
- 	}
- 
- 	pos = mgmt->u.assoc_resp.variable;
--	if (ieee802_11_parse_elems(pos, len - (pos - (u8 *) mgmt), &elems)
--	    == ParseFailed) {
--		printk(KERN_DEBUG "%s: failed to parse AssocResp\n",
--		       dev->name);
--		return;
--	}
-+	ieee802_11_parse_elems(pos, len - (pos - (u8 *) mgmt), &elems);
- 
- 	if (!elems.supp_rates) {
- 		printk(KERN_DEBUG "%s: no SuppRates element in AssocResp\n",
-@@ -1231,7 +1207,9 @@
- 	 * update our stored copy */
- 	if (elems.erp_info && elems.erp_info_len >= 1) {
- 		struct ieee80211_sta_bss *bss
--			= ieee80211_rx_bss_get(dev, ifsta->bssid);
-+			= ieee80211_rx_bss_get(dev, ifsta->bssid,
-+					       local->hw.conf.channel,
-+					       ifsta->ssid, ifsta->ssid_len);
- 		if (bss) {
- 			bss->erp_value = elems.erp_info[0];
- 			bss->has_erp_value = 1;
-@@ -1261,7 +1239,9 @@
- 			       " AP\n", dev->name);
- 			return;
- 		}
--		bss = ieee80211_rx_bss_get(dev, ifsta->bssid);
-+		bss = ieee80211_rx_bss_get(dev, ifsta->bssid,
-+					   local->hw.conf.channel,
-+					   ifsta->ssid, ifsta->ssid_len);
- 		if (bss) {
- 			sta->last_rssi = bss->rssi;
- 			sta->last_signal = bss->signal;
-@@ -1337,7 +1317,8 @@
- 
- 
- static struct ieee80211_sta_bss *
--ieee80211_rx_bss_add(struct net_device *dev, u8 *bssid)
-+ieee80211_rx_bss_add(struct net_device *dev, u8 *bssid, int channel,
-+		     u8 *ssid, u8 ssid_len)
- {
- 	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
- 	struct ieee80211_sta_bss *bss;
-@@ -1348,6 +1329,11 @@
- 	atomic_inc(&bss->users);
- 	atomic_inc(&bss->users);
- 	memcpy(bss->bssid, bssid, ETH_ALEN);
-+	bss->channel = channel;
-+	if (ssid && ssid_len <= IEEE80211_MAX_SSID_LEN) {
-+		memcpy(bss->ssid, ssid, ssid_len);
-+		bss->ssid_len = ssid_len;
-+	}
- 
- 	spin_lock_bh(&local->sta_bss_lock);
- 	/* TODO: order by RSSI? */
-@@ -1359,7 +1345,8 @@
- 
- 
- static struct ieee80211_sta_bss *
--ieee80211_rx_bss_get(struct net_device *dev, u8 *bssid)
-+ieee80211_rx_bss_get(struct net_device *dev, u8 *bssid, int channel,
-+		     u8 *ssid, u8 ssid_len)
- {
- 	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
- 	struct ieee80211_sta_bss *bss;
-@@ -1367,7 +1354,10 @@
- 	spin_lock_bh(&local->sta_bss_lock);
- 	bss = local->sta_bss_hash[STA_HASH(bssid)];
- 	while (bss) {
--		if (memcmp(bss->bssid, bssid, ETH_ALEN) == 0) {
-+		if (!memcmp(bss->bssid, bssid, ETH_ALEN) &&
-+		    bss->channel == channel &&
-+		    bss->ssid_len == ssid_len &&
-+		    (ssid_len == 0 || !memcmp(bss->ssid, ssid, ssid_len))) {
- 			atomic_inc(&bss->users);
- 			break;
- 		}
-@@ -1429,7 +1419,7 @@
- 	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
- 	struct ieee802_11_elems elems;
- 	size_t baselen;
--	int channel, invalid = 0, clen;
-+	int channel, clen;
- 	struct ieee80211_sta_bss *bss;
- 	struct sta_info *sta;
- 	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-@@ -1473,9 +1463,7 @@
- #endif /* CONFIG_MAC80211_IBSS_DEBUG */
- 	}
- 
--	if (ieee802_11_parse_elems(mgmt->u.beacon.variable, len - baselen,
--				   &elems) == ParseFailed)
--		invalid = 1;
-+	ieee802_11_parse_elems(mgmt->u.beacon.variable, len - baselen, &elems);
- 
- 	if (sdata->type == IEEE80211_IF_TYPE_IBSS && elems.supp_rates &&
- 	    memcmp(mgmt->bssid, sdata->u.sta.bssid, ETH_ALEN) == 0 &&
-@@ -1533,9 +1521,11 @@
- 	else
- 		channel = rx_status->channel;
- 
--	bss = ieee80211_rx_bss_get(dev, mgmt->bssid);
-+	bss = ieee80211_rx_bss_get(dev, mgmt->bssid, channel,
-+				   elems.ssid, elems.ssid_len);
- 	if (!bss) {
--		bss = ieee80211_rx_bss_add(dev, mgmt->bssid);
-+		bss = ieee80211_rx_bss_add(dev, mgmt->bssid, channel,
-+					   elems.ssid, elems.ssid_len);
- 		if (!bss)
- 			return;
- 	} else {
-@@ -1561,10 +1551,6 @@
- 
- 	bss->beacon_int = le16_to_cpu(mgmt->u.beacon.beacon_int);
- 	bss->capability = le16_to_cpu(mgmt->u.beacon.capab_info);
--	if (elems.ssid && elems.ssid_len <= IEEE80211_MAX_SSID_LEN) {
--		memcpy(bss->ssid, elems.ssid, elems.ssid_len);
--		bss->ssid_len = elems.ssid_len;
--	}
- 
- 	bss->supp_rates_len = 0;
- 	if (elems.supp_rates) {
-@@ -1635,7 +1621,6 @@
- 
- 
- 	bss->hw_mode = rx_status->phymode;
--	bss->channel = channel;
- 	bss->freq = rx_status->freq;
- 	if (channel != rx_status->channel &&
- 	    (bss->hw_mode == MODE_IEEE80211G ||
-@@ -1695,9 +1680,7 @@
- 	if (baselen > len)
- 		return;
- 
--	if (ieee802_11_parse_elems(mgmt->u.beacon.variable, len - baselen,
--				   &elems) == ParseFailed)
--		return;
-+	ieee802_11_parse_elems(mgmt->u.beacon.variable, len - baselen, &elems);
- 
- 	if (elems.erp_info && elems.erp_info_len >= 1)
- 		ieee80211_handle_erp_ie(dev, elems.erp_info[0]);
-@@ -2098,7 +2081,8 @@
- {
- 	int tmp, hidden_ssid;
- 
--	if (!memcmp(ifsta->ssid, ssid, ssid_len))
-+	if (ssid_len == ifsta->ssid_len &&
-+	    !memcmp(ifsta->ssid, ssid, ssid_len))
- 		return 1;
- 
- 	if (ifsta->flags & IEEE80211_STA_AUTO_BSSID_SEL)
-@@ -2357,7 +2341,7 @@
- {
- 	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
- 	struct ieee80211_sta_bss *bss;
--	struct ieee80211_sub_if_data *sdata;
-+	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
- 	struct ieee80211_hw_mode *mode;
- 	u8 bssid[ETH_ALEN], *pos;
- 	int i;
-@@ -2379,18 +2363,17 @@
- 	printk(KERN_DEBUG "%s: Creating new IBSS network, BSSID " MAC_FMT "\n",
- 	       dev->name, MAC_ARG(bssid));
- 
--	bss = ieee80211_rx_bss_add(dev, bssid);
-+	bss = ieee80211_rx_bss_add(dev, bssid, local->hw.conf.channel,
-+				   sdata->u.sta.ssid, sdata->u.sta.ssid_len);
- 	if (!bss)
- 		return -ENOMEM;
- 
--	sdata = IEEE80211_DEV_TO_SUB_IF(dev);
- 	mode = local->oper_hw_mode;
- 
- 	if (local->hw.conf.beacon_int == 0)
- 		local->hw.conf.beacon_int = 100;
- 	bss->beacon_int = local->hw.conf.beacon_int;
- 	bss->hw_mode = local->hw.conf.phymode;
--	bss->channel = local->hw.conf.channel;
- 	bss->freq = local->hw.conf.freq;
- 	bss->last_update = jiffies;
- 	bss->capability = WLAN_CAPABILITY_IBSS;
-@@ -2448,7 +2431,8 @@
- 	       MAC_FMT "\n", MAC_ARG(bssid), MAC_ARG(ifsta->bssid));
- #endif /* CONFIG_MAC80211_IBSS_DEBUG */
- 	if (found && memcmp(ifsta->bssid, bssid, ETH_ALEN) != 0 &&
--	    (bss = ieee80211_rx_bss_get(dev, bssid))) {
-+	    (bss = ieee80211_rx_bss_get(dev, bssid, local->hw.conf.channel,
-+					ifsta->ssid, ifsta->ssid_len))) {
- 		printk(KERN_DEBUG "%s: Selected IBSS BSSID " MAC_FMT
- 		       " based on configured SSID\n",
- 		       dev->name, MAC_ARG(bssid));
-Index: mac80211/net/mac80211/Kconfig
-===================================================================
---- mac80211.orig/net/mac80211/Kconfig	2007-11-11 15:45:23.225494151 +0100
-+++ mac80211/net/mac80211/Kconfig	2007-11-11 15:45:30.449905846 +0100
-@@ -13,6 +13,18 @@
- 	This option enables the hardware independent IEEE 802.11
- 	networking stack.
- 
-+config MAC80211_RCSIMPLE
-+	bool "'simple' rate control algorithm" if EMBEDDED
-+	default y
-+	depends on MAC80211
-+	help
-+	  This option allows you to turn off the 'simple' rate
-+	  control algorithm in mac80211. If you do turn it off,
-+	  you absolutely need another rate control algorithm.
-+
-+	  Say Y unless you know you will have another algorithm
-+	  available.
-+
- config MAC80211_LEDS
- 	bool "Enable LED triggers"
- 	depends on MAC80211 && LEDS_TRIGGERS
-Index: mac80211/net/mac80211/Makefile
-===================================================================
---- mac80211.orig/net/mac80211/Makefile	2007-11-11 15:45:23.233494609 +0100
-+++ mac80211/net/mac80211/Makefile	2007-11-11 15:45:30.449905846 +0100
-@@ -1,8 +1,9 @@
--obj-$(CONFIG_MAC80211) += mac80211.o rc80211_simple.o
-+obj-$(CONFIG_MAC80211) += mac80211.o
- 
- mac80211-objs-$(CONFIG_MAC80211_LEDS) += ieee80211_led.o
- mac80211-objs-$(CONFIG_MAC80211_DEBUGFS) += debugfs.o debugfs_sta.o debugfs_netdev.o debugfs_key.o
- mac80211-objs-$(CONFIG_NET_SCHED) += wme.o
-+mac80211-objs-$(CONFIG_MAC80211_RCSIMPLE) += rc80211_simple.o
- 
- mac80211-objs := \
- 	ieee80211.o \
-Index: mac80211/net/mac80211/rc80211_simple.c
-===================================================================
---- mac80211.orig/net/mac80211/rc80211_simple.c	2007-11-11 15:45:23.237494839 +0100
-+++ mac80211/net/mac80211/rc80211_simple.c	2007-11-11 15:45:30.449905846 +0100
-@@ -7,7 +7,6 @@
-  * published by the Free Software Foundation.
-  */
- 
--#include <linux/module.h>
- #include <linux/init.h>
- #include <linux/netdevice.h>
- #include <linux/types.h>
-@@ -29,8 +28,6 @@
- #define RATE_CONTROL_INTERVAL (HZ / 20)
- #define RATE_CONTROL_MIN_TX 10
- 
--MODULE_ALIAS("rc80211_default");
--
- static void rate_control_rate_inc(struct ieee80211_local *local,
- 				  struct sta_info *sta)
- {
-@@ -393,8 +390,7 @@
- }
- #endif
- 
--static struct rate_control_ops rate_control_simple = {
--	.module = THIS_MODULE,
-+struct rate_control_ops mac80211_rcsimple = {
- 	.name = "simple",
- 	.tx_status = rate_control_simple_tx_status,
- 	.get_rate = rate_control_simple_get_rate,
-@@ -409,22 +405,3 @@
- 	.remove_sta_debugfs = rate_control_simple_remove_sta_debugfs,
- #endif
- };
--
--
--static int __init rate_control_simple_init(void)
--{
--	return ieee80211_rate_control_register(&rate_control_simple);
--}
--
--
--static void __exit rate_control_simple_exit(void)
--{
--	ieee80211_rate_control_unregister(&rate_control_simple);
--}
--
--
--subsys_initcall(rate_control_simple_init);
--module_exit(rate_control_simple_exit);
--
--MODULE_DESCRIPTION("Simple rate control algorithm for ieee80211");
--MODULE_LICENSE("GPL");
-Index: mac80211/net/mac80211/rx.c
-===================================================================
---- mac80211.orig/net/mac80211/rx.c	2007-11-11 15:45:23.245495291 +0100
-+++ mac80211/net/mac80211/rx.c	2007-11-11 15:45:30.449905846 +0100
-@@ -509,9 +509,11 @@
- 		rx->key->tx_rx_count++;
- 		/* TODO: add threshold stuff again */
- 	} else {
-+#ifdef CONFIG_MAC80211_DEBUG
- 		if (net_ratelimit())
- 			printk(KERN_DEBUG "%s: RX protected frame,"
- 			       " but have no key\n", rx->dev->name);
-+#endif /* CONFIG_MAC80211_DEBUG */
- 		return TXRX_DROP;
- 	}
- 
-Index: mac80211/net/mac80211/wep.c
-===================================================================
---- mac80211.orig/net/mac80211/wep.c	2007-11-11 15:45:23.253495749 +0100
-+++ mac80211/net/mac80211/wep.c	2007-11-11 15:45:30.449905846 +0100
-@@ -16,7 +16,7 @@
- #include <linux/crypto.h>
- #include <linux/err.h>
- #include <linux/mm.h>
--#include <asm/scatterlist.h>
-+#include <linux/scatterlist.h>
- 
- #include <net/mac80211.h>
- #include "ieee80211_i.h"
-@@ -138,9 +138,7 @@
- 	*icv = cpu_to_le32(~crc32_le(~0, data, data_len));
- 
- 	crypto_blkcipher_setkey(tfm, rc4key, klen);
--	sg.page = virt_to_page(data);
--	sg.offset = offset_in_page(data);
--	sg.length = data_len + WEP_ICV_LEN;
-+	sg_init_one(&sg, data, data_len + WEP_ICV_LEN);
- 	crypto_blkcipher_encrypt(&desc, &sg, &sg, sg.length);
- }
- 
-@@ -204,9 +202,7 @@
- 	__le32 crc;
- 
- 	crypto_blkcipher_setkey(tfm, rc4key, klen);
--	sg.page = virt_to_page(data);
--	sg.offset = offset_in_page(data);
--	sg.length = data_len + WEP_ICV_LEN;
-+	sg_init_one(&sg, data, data_len + WEP_ICV_LEN);
- 	crypto_blkcipher_decrypt(&desc, &sg, &sg, sg.length);
- 
- 	crc = cpu_to_le32(~crc32_le(~0, data, data_len));
-@@ -318,9 +314,11 @@
- 
- 	if (!(rx->u.rx.status->flag & RX_FLAG_DECRYPTED)) {
- 		if (ieee80211_wep_decrypt(rx->local, rx->skb, rx->key)) {
-+#ifdef CONFIG_MAC80211_DEBUG
- 			if (net_ratelimit())
- 				printk(KERN_DEBUG "%s: RX WEP frame, decrypt "
- 				       "failed\n", rx->dev->name);
-+#endif /* CONFIG_MAC80211_DEBUG */
- 			return TXRX_DROP;
- 		}
- 	} else if (!(rx->u.rx.status->flag & RX_FLAG_IV_STRIPPED)) {
-Index: mac80211/net/wireless/Kconfig
-===================================================================
---- mac80211.orig/net/wireless/Kconfig	2007-11-11 15:45:23.261496205 +0100
-+++ mac80211/net/wireless/Kconfig	2007-11-11 15:45:30.453906075 +0100
-@@ -3,7 +3,7 @@
- 
- config NL80211
- 	bool "nl80211 new netlink interface support"
--	depends CFG80211
-+	depends on CFG80211
- 	default y
- 	---help---
-          This option turns on the new netlink interface
diff --git a/package/mac80211/patches/001-port-to-2.6.23.patch b/package/mac80211/patches/001-port-to-2.6.23.patch
new file mode 100644
index 0000000000..2e88d405e3
--- /dev/null
+++ b/package/mac80211/patches/001-port-to-2.6.23.patch
@@ -0,0 +1,231 @@
+Index: mac80211/net/mac80211/ieee80211.c
+===================================================================
+--- mac80211.orig/net/mac80211/ieee80211.c	2008-02-15 22:20:53.000000000 +0100
++++ mac80211/net/mac80211/ieee80211.c	2008-02-15 22:21:01.000000000 +0100
+@@ -21,7 +21,6 @@
+ #include <linux/wireless.h>
+ #include <linux/rtnetlink.h>
+ #include <linux/bitmap.h>
+-#include <net/net_namespace.h>
+ #include <net/cfg80211.h>
+ 
+ #include "ieee80211_i.h"
+@@ -36,6 +35,15 @@
+ 
+ #define SUPP_MCS_SET_LEN 16
+ 
++
++char *print_mac(char *buf, const u8 *addr)
++{
++	sprintf(buf, MAC_FMT,
++		addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]);
++	return buf;
++}
++
++
+ /*
+  * For seeing transmitted packets on monitor interfaces
+  * we have a radiotap header too.
+@@ -48,11 +56,13 @@ struct ieee80211_tx_status_rtap_hdr {
+ 
+ /* common interface routines */
+ 
++#if 0
+ static int header_parse_80211(const struct sk_buff *skb, unsigned char *haddr)
+ {
+ 	memcpy(haddr, skb_mac_header(skb) + 10, ETH_ALEN); /* addr2 */
+ 	return ETH_ALEN;
+ }
++#endif
+ 
+ /* must be called under mdev tx lock */
+ static void ieee80211_configure_filter(struct ieee80211_local *local)
+@@ -800,6 +810,7 @@ static void ieee80211_set_multicast_list
+ 	dev_mc_sync(local->mdev, dev);
+ }
+ 
++#if 0
+ static const struct header_ops ieee80211_header_ops = {
+ 	.create		= eth_header,
+ 	.parse		= header_parse_80211,
+@@ -807,6 +818,7 @@ static const struct header_ops ieee80211
+ 	.cache		= eth_header_cache,
+ 	.cache_update	= eth_header_cache_update,
+ };
++#endif
+ 
+ /* Must not be called for mdev */
+ void ieee80211_if_setup(struct net_device *dev)
+@@ -1455,7 +1467,7 @@ struct ieee80211_hw *ieee80211_alloc_hw(
+ 	mdev->open = ieee80211_master_open;
+ 	mdev->stop = ieee80211_master_stop;
+ 	mdev->type = ARPHRD_IEEE80211;
+-	mdev->header_ops = &ieee80211_header_ops;
++//	mdev->header_ops = &ieee80211_header_ops;
+ 	mdev->set_multicast_list = ieee80211_master_set_multicast_list;
+ 
+ 	sdata->vif.type = IEEE80211_IF_TYPE_AP;
+Index: mac80211/net/mac80211/ieee80211_i.h
+===================================================================
+--- mac80211.orig/net/mac80211/ieee80211_i.h	2008-02-15 22:20:53.000000000 +0100
++++ mac80211/net/mac80211/ieee80211_i.h	2008-02-15 22:21:37.000000000 +0100
+@@ -26,6 +26,16 @@
+ #include "ieee80211_key.h"
+ #include "sta_info.h"
+ 
++
++#define BIT(nr)		(1 << (nr))
++
++#define MAC_FMT "%02x:%02x:%02x:%02x:%02x:%02x"
++extern char *print_mac(char *buf, const u8 *addr);
++#define DECLARE_MAC_BUF(var) char var[18] __maybe_unused
++
++#define CONFIG_MAC80211_RC_DEFAULT	__stringify(__CONFIG_MAC80211_RC_DEFAULT)
++
++
+ /* ieee80211.o internal definitions, etc. These are not included into
+  * low-level drivers. */
+ 
+Index: mac80211/net/mac80211/ieee80211_ioctl.c
+===================================================================
+--- mac80211.orig/net/mac80211/ieee80211_ioctl.c	2008-02-15 22:20:53.000000000 +0100
++++ mac80211/net/mac80211/ieee80211_ioctl.c	2008-02-15 22:21:01.000000000 +0100
+@@ -207,7 +207,7 @@ static int ieee80211_ioctl_giwrange(stru
+ 	IW_EVENT_CAPA_SET(range->event_capa, SIOCGIWAP);
+ 	IW_EVENT_CAPA_SET(range->event_capa, SIOCGIWSCAN);
+ 
+-	range->scan_capa |= IW_SCAN_CAPA_ESSID;
++//	range->scan_capa |= IW_SCAN_CAPA_ESSID;
+ 
+ 	return 0;
+ }
+Index: mac80211/net/wireless/core.c
+===================================================================
+--- mac80211.orig/net/wireless/core.c	2008-02-15 22:20:53.000000000 +0100
++++ mac80211/net/wireless/core.c	2008-02-15 22:21:01.000000000 +0100
+@@ -69,7 +69,7 @@ __cfg80211_drv_from_info(struct genl_inf
+ 
+ 	if (info->attrs[NL80211_ATTR_IFINDEX]) {
+ 		ifindex = nla_get_u32(info->attrs[NL80211_ATTR_IFINDEX]);
+-		dev = dev_get_by_index(&init_net, ifindex);
++		dev = dev_get_by_index(ifindex);
+ 		if (dev) {
+ 			if (dev->ieee80211_ptr)
+ 				byifidx =
+@@ -120,7 +120,7 @@ cfg80211_get_dev_from_ifindex(int ifinde
+ 	struct net_device *dev;
+ 
+ 	mutex_lock(&cfg80211_drv_mutex);
+-	dev = dev_get_by_index(&init_net, ifindex);
++	dev = dev_get_by_index(ifindex);
+ 	if (!dev)
+ 		goto out;
+ 	if (dev->ieee80211_ptr) {
+Index: mac80211/net/wireless/nl80211.c
+===================================================================
+--- mac80211.orig/net/wireless/nl80211.c	2008-02-15 22:20:53.000000000 +0100
++++ mac80211/net/wireless/nl80211.c	2008-02-15 22:21:01.000000000 +0100
+@@ -39,7 +39,7 @@ static int get_drv_dev_by_info_ifindex(s
+ 		return -EINVAL;
+ 
+ 	ifindex = nla_get_u32(info->attrs[NL80211_ATTR_IFINDEX]);
+-	*dev = dev_get_by_index(&init_net, ifindex);
++	*dev = dev_get_by_index(ifindex);
+ 	if (!*dev)
+ 		return -ENODEV;
+ 
+@@ -959,7 +959,7 @@ static int get_vlan(struct nlattr *vlana
+ 	*vlan = NULL;
+ 
+ 	if (vlanattr) {
+-		*vlan = dev_get_by_index(&init_net, nla_get_u32(vlanattr));
++		*vlan = dev_get_by_index(nla_get_u32(vlanattr));
+ 		if (!*vlan)
+ 			return -ENODEV;
+ 		if (!(*vlan)->ieee80211_ptr)
+Index: mac80211/net/mac80211/cfg.c
+===================================================================
+--- mac80211.orig/net/mac80211/cfg.c	2008-02-15 22:20:53.000000000 +0100
++++ mac80211/net/mac80211/cfg.c	2008-02-15 22:21:01.000000000 +0100
+@@ -9,7 +9,6 @@
+ #include <linux/ieee80211.h>
+ #include <linux/nl80211.h>
+ #include <linux/rtnetlink.h>
+-#include <net/net_namespace.h>
+ #include <linux/rcupdate.h>
+ #include <net/cfg80211.h>
+ #include "ieee80211_i.h"
+@@ -68,7 +67,7 @@ static int ieee80211_del_iface(struct wi
+ 		return -ENODEV;
+ 
+ 	/* we're under RTNL */
+-	dev = __dev_get_by_index(&init_net, ifindex);
++	dev = __dev_get_by_index(ifindex);
+ 	if (!dev)
+ 		return 0;
+ 
+@@ -89,7 +88,7 @@ static int ieee80211_change_iface(struct
+ 		return -ENODEV;
+ 
+ 	/* we're under RTNL */
+-	dev = __dev_get_by_index(&init_net, ifindex);
++	dev = __dev_get_by_index(ifindex);
+ 	if (!dev)
+ 		return -ENODEV;
+ 
+Index: mac80211/net/mac80211/tx.c
+===================================================================
+--- mac80211.orig/net/mac80211/tx.c	2008-02-15 22:20:53.000000000 +0100
++++ mac80211/net/mac80211/tx.c	2008-02-15 22:21:01.000000000 +0100
+@@ -18,7 +18,6 @@
+ #include <linux/etherdevice.h>
+ #include <linux/bitmap.h>
+ #include <linux/rcupdate.h>
+-#include <net/net_namespace.h>
+ #include <net/ieee80211_radiotap.h>
+ #include <net/cfg80211.h>
+ #include <net/mac80211.h>
+@@ -1051,7 +1050,7 @@ static int ieee80211_tx_prepare(struct i
+ 	struct net_device *dev;
+ 
+ 	pkt_data = (struct ieee80211_tx_packet_data *)skb->cb;
+-	dev = dev_get_by_index(&init_net, pkt_data->ifindex);
++	dev = dev_get_by_index(pkt_data->ifindex);
+ 	if (unlikely(dev && !is_ieee80211_device(dev, mdev))) {
+ 		dev_put(dev);
+ 		dev = NULL;
+@@ -1265,7 +1264,7 @@ int ieee80211_master_start_xmit(struct s
+ 	memset(&control, 0, sizeof(struct ieee80211_tx_control));
+ 
+ 	if (pkt_data->ifindex)
+-		odev = dev_get_by_index(&init_net, pkt_data->ifindex);
++		odev = dev_get_by_index(pkt_data->ifindex);
+ 	if (unlikely(odev && !is_ieee80211_device(odev, dev))) {
+ 		dev_put(odev);
+ 		odev = NULL;
+Index: mac80211/net/mac80211/util.c
+===================================================================
+--- mac80211.orig/net/mac80211/util.c	2008-02-15 22:20:53.000000000 +0100
++++ mac80211/net/mac80211/util.c	2008-02-15 22:21:01.000000000 +0100
+@@ -20,7 +20,6 @@
+ #include <linux/if_arp.h>
+ #include <linux/wireless.h>
+ #include <linux/bitmap.h>
+-#include <net/net_namespace.h>
+ #include <net/cfg80211.h>
+ #include <net/rtnetlink.h>
+ 
+Index: mac80211/net/wireless/sysfs.c
+===================================================================
+--- mac80211.orig/net/wireless/sysfs.c	2008-02-15 22:20:53.000000000 +0100
++++ mac80211/net/wireless/sysfs.c	2008-02-15 22:21:01.000000000 +0100
+@@ -53,7 +53,8 @@ static void wiphy_dev_release(struct dev
+ }
+ 
+ #ifdef CONFIG_HOTPLUG
+-static int wiphy_uevent(struct device *dev, struct kobj_uevent_env *env)
++static int wiphy_uevent(struct device *dev, char **envp, int num_envp,
++			char *buffer, int buffer_size)
+ {
+ 	/* TODO, we probably need stuff here */
+ 	return 0;
diff --git a/package/mac80211/patches/008-add-hostapd-ioctl-header.patch b/package/mac80211/patches/008-add-hostapd-ioctl-header.patch
deleted file mode 100644
index acea0ce969..0000000000
--- a/package/mac80211/patches/008-add-hostapd-ioctl-header.patch
+++ /dev/null
@@ -1,110 +0,0 @@
----
- net/mac80211/hostapd_ioctl.h |  103 +++++++++++++++++++++++++++++++++++++++++++
- 1 file changed, 103 insertions(+)
-
---- /dev/null	1970-01-01 00:00:00.000000000 +0000
-+++ everything/net/mac80211/hostapd_ioctl.h	2007-11-07 13:19:23.031516330 +0100
-@@ -0,0 +1,103 @@
-+/*
-+ * Host AP (software wireless LAN access point) user space daemon for
-+ * Host AP kernel driver
-+ * Copyright 2002-2003, Jouni Malinen <jkmaline@cc.hut.fi>
-+ * Copyright 2002-2004, Instant802 Networks, Inc.
-+ * Copyright 2005, Devicescape Software, Inc.
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License version 2 as
-+ * published by the Free Software Foundation.
-+ */
-+
-+#ifndef HOSTAPD_IOCTL_H
-+#define HOSTAPD_IOCTL_H
-+
-+#ifdef __KERNEL__
-+#include <linux/types.h>
-+#endif /* __KERNEL__ */
-+
-+#define PRISM2_IOCTL_PRISM2_PARAM (SIOCIWFIRSTPRIV + 0)
-+#define PRISM2_IOCTL_GET_PRISM2_PARAM (SIOCIWFIRSTPRIV + 1)
-+#define PRISM2_IOCTL_HOSTAPD (SIOCIWFIRSTPRIV + 3)
-+
-+/* PRISM2_IOCTL_PRISM2_PARAM ioctl() subtypes:
-+ * This table is no longer added to, the whole sub-ioctl
-+ * mess shall be deleted completely. */
-+enum {
-+	PRISM2_PARAM_AP_BRIDGE_PACKETS = 10,
-+	PRISM2_PARAM_IEEE_802_1X = 23,
-+
-+	/* Instant802 additions */
-+	PRISM2_PARAM_CTS_PROTECT_ERP_FRAMES = 1001,
-+	PRISM2_PARAM_PREAMBLE = 1003,
-+	PRISM2_PARAM_SHORT_SLOT_TIME = 1006,
-+	PRISM2_PARAM_NEXT_MODE = 1008,
-+	PRISM2_PARAM_PRIVACY_INVOKED = 1014,
-+	PRISM2_PARAM_EAPOL = 1023,
-+	PRISM2_PARAM_MGMT_IF = 1046,
-+};
-+
-+/* PRISM2_IOCTL_HOSTAPD ioctl() cmd:
-+ * This table is no longer added to, the hostapd ioctl
-+ * shall be deleted completely. */
-+enum {
-+	PRISM2_HOSTAPD_FLUSH = 1,
-+
-+	/* Instant802 additions */
-+	PRISM2_HOSTAPD_GET_HW_FEATURES = 1002,
-+	PRISM2_HOSTAPD_SET_RATE_SETS = 1005,
-+	PRISM2_HOSTAPD_SET_CHANNEL_FLAG = 1012,
-+	PRISM2_HOSTAPD_SET_REGULATORY_DOMAIN = 1013,
-+	PRISM2_HOSTAPD_SET_TX_QUEUE_PARAMS = 1014,
-+};
-+
-+#define PRISM2_HOSTAPD_MAX_BUF_SIZE 2048
-+#define ALIGNED __attribute__ ((aligned))
-+
-+struct prism2_hostapd_param {
-+	u32 cmd;
-+	u8 sta_addr[ETH_ALEN];
-+	u8 pad[2];
-+	union {
-+		struct {
-+			u16 num_modes;
-+			u16 flags;
-+			u8 data[0] ALIGNED; /* num_modes * feature data */
-+		} hw_features;
-+		struct {
-+			u16 mode; /* MODE_* */
-+			u16 num_supported_rates;
-+			u16 num_basic_rates;
-+			u8 data[0] ALIGNED; /* num_supported_rates * u16 +
-+					     * num_basic_rates * u16 */
-+		} set_rate_sets;
-+		struct {
-+			u16 mode; /* MODE_* */
-+			u16 chan;
-+			u32 flag;
-+			u8 power_level; /* regulatory limit in dBm */
-+			u8 antenna_max;
-+		} set_channel_flag;
-+		struct {
-+			u32 rd;
-+		} set_regulatory_domain;
-+		struct {
-+			u32 queue;
-+			s32 aifs;
-+			u32 cw_min;
-+			u32 cw_max;
-+			u32 burst_time; /* maximum burst time in 0.1 ms, i.e.,
-+					 * 10 = 1 ms */
-+		} tx_queue_params;
-+	} u;
-+};
-+
-+/* Data structures used for get_hw_features ioctl */
-+struct hostapd_ioctl_hw_modes_hdr {
-+	int mode;
-+	int num_channels;
-+	int num_rates;
-+};
-+
-+#endif /* HOSTAPD_IOCTL_H */
diff --git a/package/mac80211/patches/009-add-old-ioctl-skeleton.patch b/package/mac80211/patches/009-add-old-ioctl-skeleton.patch
deleted file mode 100644
index fb9f25f62a..0000000000
--- a/package/mac80211/patches/009-add-old-ioctl-skeleton.patch
+++ /dev/null
@@ -1,187 +0,0 @@
----
- net/mac80211/ieee80211.c       |    5 +
- net/mac80211/ieee80211_ioctl.c |  121 +++++++++++++++++++++++++++++++++++++++++
- 2 files changed, 126 insertions(+)
-
---- everything.orig/net/mac80211/ieee80211_ioctl.c	2007-11-07 13:06:34.902124618 +0100
-+++ everything/net/mac80211/ieee80211_ioctl.c	2007-11-07 13:19:24.311521482 +0100
-@@ -21,6 +21,7 @@
- 
- #include <net/mac80211.h>
- #include "ieee80211_i.h"
-+#include "hostapd_ioctl.h"
- #include "ieee80211_rate.h"
- #include "wpa.h"
- #include "aes_ccm.h"
-@@ -124,6 +125,47 @@ static int ieee80211_ioctl_siwgenie(stru
- 	return -EOPNOTSUPP;
- }
- 
-+
-+static int ieee80211_ioctl_priv_hostapd(struct net_device *dev,
-+					struct iw_point *p)
-+{
-+	struct prism2_hostapd_param *param;
-+	int ret = 0;
-+
-+	if (p->length < sizeof(struct prism2_hostapd_param) ||
-+	    p->length > PRISM2_HOSTAPD_MAX_BUF_SIZE || !p->pointer) {
-+		printk(KERN_DEBUG "%s: hostapd ioctl: ptr=%p len=%d min=%d "
-+		       "max=%d\n", dev->name, p->pointer, p->length,
-+		       (int)sizeof(struct prism2_hostapd_param),
-+		       PRISM2_HOSTAPD_MAX_BUF_SIZE);
-+		return -EINVAL;
-+	}
-+
-+	param = kmalloc(p->length, GFP_KERNEL);
-+	if (!param)
-+		return -ENOMEM;
-+
-+	if (copy_from_user(param, p->pointer, p->length)) {
-+		ret = -EFAULT;
-+		goto out;
-+	}
-+
-+	switch (param->cmd) {
-+	default:
-+		ret = -EOPNOTSUPP;
-+		break;
-+	}
-+
-+	if (copy_to_user(p->pointer, param, p->length))
-+		ret = -EFAULT;
-+
-+ out:
-+	kfree(param);
-+
-+	return ret;
-+}
-+
-+
- static int ieee80211_ioctl_giwname(struct net_device *dev,
- 				   struct iw_request_info *info,
- 				   char *name, char *extra)
-@@ -819,6 +861,49 @@ static int ieee80211_ioctl_giwretry(stru
- 	return 0;
- }
- 
-+static int ieee80211_ioctl_prism2_param(struct net_device *dev,
-+					struct iw_request_info *info,
-+					void *wrqu, char *extra)
-+{
-+	struct ieee80211_sub_if_data *sdata;
-+	int *i = (int *) extra;
-+	int param = *i;
-+	int ret = 0;
-+
-+	if (!capable(CAP_NET_ADMIN))
-+		return -EPERM;
-+
-+	sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-+
-+	switch (param) {
-+	default:
-+		ret = -EOPNOTSUPP;
-+		break;
-+	}
-+
-+	return ret;
-+}
-+
-+
-+static int ieee80211_ioctl_get_prism2_param(struct net_device *dev,
-+					    struct iw_request_info *info,
-+					    void *wrqu, char *extra)
-+{
-+	struct ieee80211_sub_if_data *sdata;
-+	int *param = (int *) extra;
-+	int ret = 0;
-+
-+	sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-+
-+	switch (*param) {
-+	default:
-+		ret = -EOPNOTSUPP;
-+		break;
-+	}
-+
-+	return ret;
-+}
-+
- static int ieee80211_ioctl_siwmlme(struct net_device *dev,
- 				   struct iw_request_info *info,
- 				   struct iw_point *data, char *extra)
-@@ -1073,6 +1158,32 @@ static int ieee80211_ioctl_siwencodeext(
- }
- 
- 
-+static const struct iw_priv_args ieee80211_ioctl_priv[] = {
-+	{ PRISM2_IOCTL_PRISM2_PARAM,
-+	  IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 2, 0, "param" },
-+	{ PRISM2_IOCTL_GET_PRISM2_PARAM,
-+	  IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
-+	  IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "get_param" },
-+};
-+
-+
-+int ieee80211_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
-+{
-+	struct iwreq *wrq = (struct iwreq *) rq;
-+
-+	switch (cmd) {
-+		/* Private ioctls (iwpriv) that have not yet been converted
-+		 * into new wireless extensions API */
-+	case PRISM2_IOCTL_HOSTAPD:
-+		if (!capable(CAP_NET_ADMIN))
-+			return -EPERM;
-+		return ieee80211_ioctl_priv_hostapd(dev, &wrq->u.data);
-+	default:
-+		return -EOPNOTSUPP;
-+	}
-+}
-+
-+
- /* Structures to export the Wireless Handlers */
- 
- static const iw_handler ieee80211_handler[] =
-@@ -1135,9 +1246,19 @@ static const iw_handler ieee80211_handle
- 	(iw_handler) NULL,				/* -- hole -- */
- };
- 
-+static const iw_handler ieee80211_private_handler[] =
-+{							/* SIOCIWFIRSTPRIV + */
-+	(iw_handler) ieee80211_ioctl_prism2_param,	/* 0 */
-+	(iw_handler) ieee80211_ioctl_get_prism2_param,	/* 1 */
-+};
-+
- const struct iw_handler_def ieee80211_iw_handler_def =
- {
- 	.num_standard	= ARRAY_SIZE(ieee80211_handler),
-+	.num_private	= ARRAY_SIZE(ieee80211_private_handler),
-+	.num_private_args = ARRAY_SIZE(ieee80211_ioctl_priv),
- 	.standard	= (iw_handler *) ieee80211_handler,
-+	.private	= (iw_handler *) ieee80211_private_handler,
-+	.private_args	= (struct iw_priv_args *) ieee80211_ioctl_priv,
- 	.get_wireless_stats = ieee80211_get_wireless_stats,
- };
---- everything.orig/net/mac80211/ieee80211.c	2007-11-07 13:18:36.001511500 +0100
-+++ everything/net/mac80211/ieee80211.c	2007-11-07 13:19:24.311521482 +0100
-@@ -413,6 +413,9 @@ static const struct header_ops ieee80211
- 	.cache_update	= eth_header_cache_update,
- };
- 
-+/* HACK */
-+extern int ieee80211_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
-+
- /* Must not be called for mdev */
- void ieee80211_if_setup(struct net_device *dev)
- {
-@@ -425,6 +428,8 @@ void ieee80211_if_setup(struct net_devic
- 	dev->open = ieee80211_open;
- 	dev->stop = ieee80211_stop;
- 	dev->destructor = ieee80211_if_free;
-+
-+	dev->do_ioctl = ieee80211_ioctl;
- }
- 
- /* WDS specialties */
diff --git a/package/mac80211/patches/010-add-mgmt-iface.patch b/package/mac80211/patches/010-add-mgmt-iface.patch
deleted file mode 100644
index eae5ff6d5e..0000000000
--- a/package/mac80211/patches/010-add-mgmt-iface.patch
+++ /dev/null
@@ -1,688 +0,0 @@
----
- include/net/mac80211.h          |    1 
- net/mac80211/ieee80211.c        |  198 ++++++++++++++++++++++++++++++++++++++--
- net/mac80211/ieee80211_common.h |   64 ++++++++++++
- net/mac80211/ieee80211_i.h      |    9 +
- net/mac80211/ieee80211_iface.c  |   66 +++++++++++++
- net/mac80211/ieee80211_ioctl.c  |   21 ++++
- net/mac80211/ieee80211_rate.c   |    3 
- net/mac80211/ieee80211_rate.h   |    2 
- net/mac80211/ieee80211_sta.c    |    2 
- net/mac80211/rx.c               |   29 ++++-
- net/mac80211/tx.c               |   14 ++
- net/mac80211/wme.c              |   10 +-
- 12 files changed, 399 insertions(+), 20 deletions(-)
-
-Index: mac80211/include/net/mac80211.h
-===================================================================
---- mac80211.orig/include/net/mac80211.h	2007-11-11 15:15:42.824034853 +0100
-+++ mac80211/include/net/mac80211.h	2007-11-11 15:15:53.784659457 +0100
-@@ -472,6 +472,7 @@
- enum ieee80211_if_types {
- 	IEEE80211_IF_TYPE_INVALID,
- 	IEEE80211_IF_TYPE_AP,
-+	IEEE80211_IF_TYPE_MGMT,
- 	IEEE80211_IF_TYPE_STA,
- 	IEEE80211_IF_TYPE_IBSS,
- 	IEEE80211_IF_TYPE_MNTR,
-Index: mac80211/net/mac80211/ieee80211.c
-===================================================================
---- mac80211.orig/net/mac80211/ieee80211.c	2007-11-11 15:15:51.536531354 +0100
-+++ mac80211/net/mac80211/ieee80211.c	2007-11-11 15:16:22.214279577 +0100
-@@ -23,6 +23,7 @@
- #include <linux/bitmap.h>
- #include <net/cfg80211.h>
- 
-+#include "ieee80211_common.h"
- #include "ieee80211_i.h"
- #include "ieee80211_rate.h"
- #include "wep.h"
-@@ -121,6 +122,152 @@
- 	ieee80211_configure_filter(local);
- }
- 
-+/* management interface */
-+
-+static void
-+ieee80211_fill_frame_info(struct ieee80211_local *local,
-+			  struct ieee80211_frame_info *fi,
-+			  struct ieee80211_rx_status *status)
-+{
-+	if (status) {
-+		struct timespec ts;
-+		struct ieee80211_rate *rate;
-+
-+		jiffies_to_timespec(jiffies, &ts);
-+		fi->hosttime = cpu_to_be64((u64) ts.tv_sec * 1000000 +
-+					   ts.tv_nsec / 1000);
-+		fi->mactime = cpu_to_be64(status->mactime);
-+		switch (status->phymode) {
-+		case MODE_IEEE80211A:
-+			fi->phytype = htonl(ieee80211_phytype_ofdm_dot11_a);
-+			break;
-+		case MODE_IEEE80211B:
-+			fi->phytype = htonl(ieee80211_phytype_dsss_dot11_b);
-+			break;
-+		case MODE_IEEE80211G:
-+			fi->phytype = htonl(ieee80211_phytype_pbcc_dot11_g);
-+			break;
-+		default:
-+			fi->phytype = htonl(0xAAAAAAAA);
-+			break;
-+		}
-+		fi->channel = htonl(status->channel);
-+		rate = ieee80211_get_rate(local, status->phymode,
-+					  status->rate);
-+		if (rate) {
-+			fi->datarate = htonl(rate->rate);
-+			if (rate->flags & IEEE80211_RATE_PREAMBLE2) {
-+				if (status->rate == rate->val)
-+					fi->preamble = htonl(2); /* long */
-+				else if (status->rate == rate->val2)
-+					fi->preamble = htonl(1); /* short */
-+			} else
-+				fi->preamble = htonl(0);
-+		} else {
-+			fi->datarate = htonl(0);
-+			fi->preamble = htonl(0);
-+		}
-+
-+		fi->antenna = htonl(status->antenna);
-+		fi->priority = htonl(0xffffffff); /* no clue */
-+		fi->ssi_type = htonl(ieee80211_ssi_raw);
-+		fi->ssi_signal = htonl(status->ssi);
-+		fi->ssi_noise = 0x00000000;
-+		fi->encoding = 0;
-+	} else {
-+		/* clear everything because we really don't know.
-+		 * the msg_type field isn't present on monitor frames
-+		 * so we don't know whether it will be present or not,
-+		 * but it's ok to not clear it since it'll be assigned
-+		 * anyway */
-+		memset(fi, 0, sizeof(*fi) - sizeof(fi->msg_type));
-+
-+		fi->ssi_type = htonl(ieee80211_ssi_none);
-+	}
-+	fi->version = htonl(IEEE80211_FI_VERSION);
-+	fi->length = cpu_to_be32(sizeof(*fi) - sizeof(fi->msg_type));
-+}
-+
-+/* this routine is actually not just for this, but also
-+ * for pushing fake 'management' frames into userspace.
-+ * it shall be replaced by a netlink-based system. */
-+void
-+ieee80211_rx_mgmt(struct ieee80211_local *local, struct sk_buff *skb,
-+		  struct ieee80211_rx_status *status, u32 msg_type)
-+{
-+	struct ieee80211_frame_info *fi;
-+	const size_t hlen = sizeof(struct ieee80211_frame_info);
-+	struct net_device *dev = local->apdev;
-+
-+	skb->dev = dev;
-+
-+	if (skb_headroom(skb) < hlen) {
-+		I802_DEBUG_INC(local->rx_expand_skb_head);
-+		if (pskb_expand_head(skb, hlen, 0, GFP_ATOMIC)) {
-+			dev_kfree_skb(skb);
-+			return;
-+		}
-+	}
-+
-+	fi = (struct ieee80211_frame_info *) skb_push(skb, hlen);
-+
-+	ieee80211_fill_frame_info(local, fi, status);
-+	fi->msg_type = htonl(msg_type);
-+
-+	dev->stats.rx_packets++;
-+	dev->stats.rx_bytes += skb->len;
-+
-+	skb_set_mac_header(skb, 0);
-+	skb->ip_summed = CHECKSUM_UNNECESSARY;
-+	skb->pkt_type = PACKET_OTHERHOST;
-+	skb->protocol = htons(ETH_P_802_2);
-+	memset(skb->cb, 0, sizeof(skb->cb));
-+	netif_rx(skb);
-+}
-+
-+static int ieee80211_mgmt_open(struct net_device *dev)
-+{
-+	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
-+
-+	if (!netif_running(local->mdev))
-+		return -EOPNOTSUPP;
-+	return 0;
-+}
-+
-+static int ieee80211_mgmt_stop(struct net_device *dev)
-+{
-+	return 0;
-+}
-+
-+static int ieee80211_change_mtu_apdev(struct net_device *dev, int new_mtu)
-+{
-+	/* FIX: what would be proper limits for MTU?
-+	 * This interface uses 802.11 frames. */
-+	if (new_mtu < 256 || new_mtu > IEEE80211_MAX_DATA_LEN) {
-+		printk(KERN_WARNING "%s: invalid MTU %d\n",
-+		       dev->name, new_mtu);
-+		return -EINVAL;
-+	}
-+
-+#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
-+	printk(KERN_DEBUG "%s: setting MTU %d\n", dev->name, new_mtu);
-+#endif /* CONFIG_MAC80211_VERBOSE_DEBUG */
-+	dev->mtu = new_mtu;
-+	return 0;
-+}
-+
-+void ieee80211_if_mgmt_setup(struct net_device *dev)
-+{
-+	ether_setup(dev);
-+	dev->hard_start_xmit = ieee80211_mgmt_start_xmit;
-+	dev->change_mtu = ieee80211_change_mtu_apdev;
-+	dev->open = ieee80211_mgmt_open;
-+	dev->stop = ieee80211_mgmt_stop;
-+	dev->type = ARPHRD_IEEE80211_PRISM;
-+	dev->hard_header_parse = &header_parse_80211;
-+	dev->destructor = ieee80211_if_free;
-+}
-+
- /* regular interfaces */
- 
- static int ieee80211_change_mtu(struct net_device *dev, int new_mtu)
-@@ -198,6 +345,7 @@
- 			return -ENOLINK;
- 		break;
- 	case IEEE80211_IF_TYPE_AP:
-+	case IEEE80211_IF_TYPE_MGMT:
- 	case IEEE80211_IF_TYPE_STA:
- 	case IEEE80211_IF_TYPE_MNTR:
- 	case IEEE80211_IF_TYPE_IBSS:
-@@ -262,6 +410,10 @@
- 	if (local->open_count == 0) {
- 		res = dev_open(local->mdev);
- 		WARN_ON(res);
-+		if (local->apdev) {
-+			res = dev_open(local->apdev);
-+			WARN_ON(res);
-+		}
- 		tasklet_enable(&local->tx_pending_tasklet);
- 		tasklet_enable(&local->tasklet);
- 	}
-@@ -347,6 +499,9 @@
- 		if (netif_running(local->mdev))
- 			dev_close(local->mdev);
- 
-+		if (local->apdev)
-+			dev_close(local->apdev);
-+
- 		if (local->ops->stop)
- 			local->ops->stop(local_to_hw(local));
- 
-@@ -646,6 +801,8 @@
- 		pkt_data->flags |= IEEE80211_TXPD_DO_NOT_ENCRYPT;
- 	if (control->flags & IEEE80211_TXCTL_REQUEUE)
- 		pkt_data->flags |= IEEE80211_TXPD_REQUEUE;
-+	if (control->type == IEEE80211_IF_TYPE_MGMT)
-+		pkt_data->flags |= IEEE80211_TXPD_MGMT_IFACE;
- 	pkt_data->queue = control->queue;
- 
- 	hdrlen = ieee80211_get_hdrlen_from_skb(skb);
-@@ -698,6 +855,7 @@
- 	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
- 	struct ieee80211_local *local = hw_to_local(hw);
- 	u16 frag, type;
-+	u32 msg_type;
- 	struct ieee80211_tx_status_rtap_hdr *rthdr;
- 	struct ieee80211_sub_if_data *sdata;
- 	int monitors;
-@@ -812,9 +970,29 @@
- 			local->dot11FailedCount++;
- 	}
- 
-+	msg_type = (status->flags & IEEE80211_TX_STATUS_ACK) ?
-+		ieee80211_msg_tx_callback_ack : ieee80211_msg_tx_callback_fail;
-+
- 	/* this was a transmitted frame, but now we want to reuse it */
- 	skb_orphan(skb);
- 
-+	if ((status->control.flags & IEEE80211_TXCTL_REQ_TX_STATUS) &&
-+	    local->apdev) {
-+		if (local->monitors) {
-+			skb2 = skb_clone(skb, GFP_ATOMIC);
-+		} else {
-+			skb2 = skb;
-+			skb = NULL;
-+		}
-+
-+		if (skb2)
-+			/* Send frame to hostapd */
-+			ieee80211_rx_mgmt(local, skb2, NULL, msg_type);
-+
-+		if (!skb)
-+			return;
-+	}
-+
- 	if (!local->monitors) {
- 		dev_kfree_skb(skb);
- 		return;
-@@ -1161,6 +1339,8 @@
- 	BUG_ON(local->reg_state != IEEE80211_DEV_REGISTERED);
- 
- 	local->reg_state = IEEE80211_DEV_UNREGISTERED;
-+	if (local->apdev)
-+		ieee80211_if_del_mgmt(local);
- 
- 	/*
- 	 * At this point, interface list manipulations are fine
-Index: mac80211/net/mac80211/ieee80211_i.h
-===================================================================
---- mac80211.orig/net/mac80211/ieee80211_i.h	2007-11-11 15:15:42.840035769 +0100
-+++ mac80211/net/mac80211/ieee80211_i.h	2007-11-11 15:15:53.792659922 +0100
-@@ -142,6 +142,7 @@
- 			 * when using CTS protection with IEEE 802.11g. */
- 			struct ieee80211_rate *last_frag_rate;
- 			int last_frag_hwrate;
-+			int mgmt_interface;
- 
- 			/* Extra fragments (in addition to the first fragment
- 			 * in skb) */
-@@ -163,6 +164,7 @@
- #define IEEE80211_TXPD_REQ_TX_STATUS	BIT(0)
- #define IEEE80211_TXPD_DO_NOT_ENCRYPT	BIT(1)
- #define IEEE80211_TXPD_REQUEUE		BIT(2)
-+#define IEEE80211_TXPD_MGMT_IFACE	BIT(3)
- /* Stored in sk_buff->cb */
- struct ieee80211_tx_packet_data {
- 	int ifindex;
-@@ -408,6 +410,7 @@
- 	struct list_head modes_list;
- 
- 	struct net_device *mdev; /* wmaster# - "master" 802.11 device */
-+	struct net_device *apdev; /* wlan#ap - management frames (hostapd) */
- 	int open_count;
- 	int monitors;
- 	unsigned int filter_flags; /* FIF_* */
-@@ -701,11 +704,14 @@
- int ieee80211_hw_config(struct ieee80211_local *local);
- int ieee80211_if_config(struct net_device *dev);
- int ieee80211_if_config_beacon(struct net_device *dev);
-+void ieee80211_rx_mgmt(struct ieee80211_local *local, struct sk_buff *skb,
-+		       struct ieee80211_rx_status *status, u32 msg_type);
- void ieee80211_prepare_rates(struct ieee80211_local *local,
- 			     struct ieee80211_hw_mode *mode);
- void ieee80211_tx_set_iswep(struct ieee80211_txrx_data *tx);
- int ieee80211_if_update_wds(struct net_device *dev, u8 *remote_addr);
- void ieee80211_if_setup(struct net_device *dev);
-+void ieee80211_if_mgmt_setup(struct net_device *dev);
- struct ieee80211_rate *ieee80211_get_rate(struct ieee80211_local *local,
- 					  int phymode, int hwrate);
- 
-@@ -772,6 +778,8 @@
- int ieee80211_if_remove(struct net_device *dev, const char *name, int id);
- void ieee80211_if_free(struct net_device *dev);
- void ieee80211_if_sdata_init(struct ieee80211_sub_if_data *sdata);
-+int ieee80211_if_add_mgmt(struct ieee80211_local *local);
-+void ieee80211_if_del_mgmt(struct ieee80211_local *local);
- 
- /* regdomain.c */
- void ieee80211_regdomain_init(void);
-@@ -788,6 +796,7 @@
- int ieee80211_master_start_xmit(struct sk_buff *skb, struct net_device *dev);
- int ieee80211_monitor_start_xmit(struct sk_buff *skb, struct net_device *dev);
- int ieee80211_subif_start_xmit(struct sk_buff *skb, struct net_device *dev);
-+int ieee80211_mgmt_start_xmit(struct sk_buff *skb, struct net_device *dev);
- 
- /* utility functions/constants */
- extern void *mac80211_wiphy_privid; /* for wiphy privid */
-Index: mac80211/net/mac80211/ieee80211_iface.c
-===================================================================
---- mac80211.orig/net/mac80211/ieee80211_iface.c	2007-11-11 15:15:42.848036222 +0100
-+++ mac80211/net/mac80211/ieee80211_iface.c	2007-11-11 15:15:53.796660158 +0100
-@@ -96,6 +96,66 @@
- 	return ret;
- }
- 
-+int ieee80211_if_add_mgmt(struct ieee80211_local *local)
-+{
-+	struct net_device *ndev;
-+	struct ieee80211_sub_if_data *nsdata;
-+	int ret;
-+
-+	ASSERT_RTNL();
-+
-+	ndev = alloc_netdev(sizeof(struct ieee80211_sub_if_data), "wmgmt%d",
-+			    ieee80211_if_mgmt_setup);
-+	if (!ndev)
-+		return -ENOMEM;
-+	ret = dev_alloc_name(ndev, ndev->name);
-+	if (ret < 0)
-+		goto fail;
-+
-+	memcpy(ndev->dev_addr, local->hw.wiphy->perm_addr, ETH_ALEN);
-+	SET_NETDEV_DEV(ndev, wiphy_dev(local->hw.wiphy));
-+
-+	nsdata = IEEE80211_DEV_TO_SUB_IF(ndev);
-+	ndev->ieee80211_ptr = &nsdata->wdev;
-+	nsdata->wdev.wiphy = local->hw.wiphy;
-+	nsdata->type = IEEE80211_IF_TYPE_MGMT;
-+	nsdata->dev = ndev;
-+	nsdata->local = local;
-+	ieee80211_if_sdata_init(nsdata);
-+
-+	ret = register_netdevice(ndev);
-+	if (ret)
-+		goto fail;
-+
-+	/*
-+	 * Called even when register_netdevice fails, it would
-+	 * oops if assigned before initialising the rest.
-+	 */
-+	ndev->uninit = ieee80211_if_reinit;
-+
-+	ieee80211_debugfs_add_netdev(nsdata);
-+
-+	if (local->open_count > 0)
-+		dev_open(ndev);
-+	local->apdev = ndev;
-+	return 0;
-+
-+fail:
-+	free_netdev(ndev);
-+	return ret;
-+}
-+
-+void ieee80211_if_del_mgmt(struct ieee80211_local *local)
-+{
-+	struct net_device *apdev;
-+
-+	ASSERT_RTNL();
-+	apdev = local->apdev;
-+	ieee80211_debugfs_remove_netdev(IEEE80211_DEV_TO_SUB_IF(apdev));
-+	local->apdev = NULL;
-+	unregister_netdevice(apdev);
-+}
-+
- void ieee80211_if_set_type(struct net_device *dev, int type)
- {
- 	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-@@ -183,6 +243,9 @@
- 	ieee80211_if_sdata_deinit(sdata);
- 
- 	switch (sdata->type) {
-+	case IEEE80211_IF_TYPE_MGMT:
-+		/* nothing to do */
-+		break;
- 	case IEEE80211_IF_TYPE_INVALID:
- 		/* cannot happen */
- 		WARN_ON(1);
-@@ -294,8 +357,11 @@
- 
- void ieee80211_if_free(struct net_device *dev)
- {
-+	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
- 	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
- 
-+	/* local->apdev must be NULL when freeing management interface */
-+	BUG_ON(dev == local->apdev);
- 	ieee80211_if_sdata_deinit(sdata);
- 	free_netdev(dev);
- }
-Index: mac80211/net/mac80211/ieee80211_rate.c
-===================================================================
---- mac80211.orig/net/mac80211/ieee80211_rate.c	2007-11-11 15:15:42.852036451 +0100
-+++ mac80211/net/mac80211/ieee80211_rate.c	2007-11-11 15:15:53.800660386 +0100
-@@ -145,7 +145,8 @@
- 	struct rate_control_ref *ref, *old;
- 
- 	ASSERT_RTNL();
--	if (local->open_count || netif_running(local->mdev))
-+	if (local->open_count || netif_running(local->mdev) ||
-+	    (local->apdev && netif_running(local->apdev)))
- 		return -EBUSY;
- 
- 	ref = rate_control_alloc(name, local);
-Index: mac80211/net/mac80211/ieee80211_rate.h
-===================================================================
---- mac80211.orig/net/mac80211/ieee80211_rate.h	2007-11-11 15:15:42.860036908 +0100
-+++ mac80211/net/mac80211/ieee80211_rate.h	2007-11-11 15:15:53.800660386 +0100
-@@ -30,6 +30,8 @@
- 
- 	/* parameters from the caller to rate_control_get_rate(): */
- 	struct ieee80211_hw_mode *mode;
-+	int mgmt_data; /* this is data frame that is used for management
-+			* (e.g., IEEE 802.1X EAPOL) */
- 	u16 ethertype;
- };
- 
-Index: mac80211/net/mac80211/ieee80211_sta.c
-===================================================================
---- mac80211.orig/net/mac80211/ieee80211_sta.c	2007-11-11 15:15:42.868037362 +0100
-+++ mac80211/net/mac80211/ieee80211_sta.c	2007-11-11 15:15:53.800660386 +0100
-@@ -475,6 +475,8 @@
- 	pkt_data = (struct ieee80211_tx_packet_data *) skb->cb;
- 	memset(pkt_data, 0, sizeof(struct ieee80211_tx_packet_data));
- 	pkt_data->ifindex = sdata->dev->ifindex;
-+	if (sdata->type == IEEE80211_IF_TYPE_MGMT)
-+		pkt_data->flags |= IEEE80211_TXPD_MGMT_IFACE;
- 	if (!encrypt)
- 		pkt_data->flags |= IEEE80211_TXPD_DO_NOT_ENCRYPT;
- 
-Index: mac80211/net/mac80211/rx.c
-===================================================================
---- mac80211.orig/net/mac80211/rx.c	2007-11-11 15:15:42.872037591 +0100
-+++ mac80211/net/mac80211/rx.c	2007-11-11 15:15:53.804660611 +0100
-@@ -19,6 +19,7 @@
- 
- #include "ieee80211_i.h"
- #include "ieee80211_led.h"
-+#include "ieee80211_common.h"
- #include "wep.h"
- #include "wpa.h"
- #include "tkip.h"
-@@ -411,7 +412,12 @@
- 			return TXRX_DROP;
- 		}
- 
--		return TXRX_DROP;
-+		if (!rx->local->apdev)
-+			return TXRX_DROP;
-+
-+		ieee80211_rx_mgmt(rx->local, rx->skb, rx->u.rx.status,
-+				  ieee80211_msg_sta_not_assoc);
-+		return TXRX_QUEUED;
- 	}
- 
- 	return TXRX_CONTINUE;
-@@ -953,8 +959,15 @@
- {
- 	if (rx->sdata->eapol && ieee80211_is_eapol(rx->skb) &&
- 	    rx->sdata->type != IEEE80211_IF_TYPE_STA &&
--	    (rx->flags & IEEE80211_TXRXD_RXRA_MATCH))
--		return TXRX_CONTINUE;
-+	    (rx->flags & IEEE80211_TXRXD_RXRA_MATCH)) {
-+		/* Pass both encrypted and unencrypted EAPOL frames to user
-+		 * space for processing. */
-+		if (!rx->local->apdev)
-+			return TXRX_DROP;
-+		ieee80211_rx_mgmt(rx->local, rx->skb, rx->u.rx.status,
-+				  ieee80211_msg_normal);
-+		return TXRX_QUEUED;
-+	}
- 
- 	if (unlikely(rx->sdata->ieee802_1x &&
- 		     (rx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA &&
-@@ -1196,8 +1209,13 @@
- 	     sdata->type == IEEE80211_IF_TYPE_IBSS) &&
- 	    !(sdata->flags & IEEE80211_SDATA_USERSPACE_MLME))
- 		ieee80211_sta_rx_mgmt(rx->dev, rx->skb, rx->u.rx.status);
--	else
--		return TXRX_DROP;
-+	else {
-+		/* Management frames are sent to hostapd for processing */
-+		if (!rx->local->apdev)
-+			return TXRX_DROP;
-+		ieee80211_rx_mgmt(rx->local, rx->skb, rx->u.rx.status,
-+				  ieee80211_msg_normal);
-+	}
- 
- 	return TXRX_QUEUED;
- }
-@@ -1407,6 +1425,7 @@
- 		/* take everything */
- 		break;
- 	case IEEE80211_IF_TYPE_INVALID:
-+	case IEEE80211_IF_TYPE_MGMT:
- 		/* should never get here */
- 		WARN_ON(1);
- 		break;
-Index: mac80211/net/mac80211/tx.c
-===================================================================
---- mac80211.orig/net/mac80211/tx.c	2007-11-11 15:15:42.880038048 +0100
-+++ mac80211/net/mac80211/tx.c	2007-11-11 15:15:53.804660611 +0100
-@@ -258,7 +258,7 @@
- 		return TXRX_CONTINUE;
- 	}
- 
--	if (unlikely(/* !injected && */ tx->sdata->ieee802_1x &&
-+	if (unlikely(!tx->u.tx.mgmt_interface && tx->sdata->ieee802_1x &&
- 		     !(sta_flags & WLAN_STA_AUTHORIZED))) {
- #ifdef CONFIG_MAC80211_VERBOSE_DEBUG
- 		printk(KERN_DEBUG "%s: dropped frame to " MAC_FMT
-@@ -568,6 +568,8 @@
- 		memset(&extra, 0, sizeof(extra));
- 		extra.mode = tx->u.tx.mode;
- 		extra.ethertype = tx->ethertype;
-+		extra.mgmt_data = tx->sdata &&
-+				  tx->sdata->type == IEEE80211_IF_TYPE_MGMT;
- 
- 		tx->u.tx.rate = rate_control_get_rate(tx->local, tx->dev,
- 						      tx->skb, &extra);
-@@ -1076,7 +1078,7 @@
- }
- 
- static int ieee80211_tx(struct net_device *dev, struct sk_buff *skb,
--			struct ieee80211_tx_control *control)
-+			struct ieee80211_tx_control *control, int mgmt)
- {
- 	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
- 	struct sta_info *sta;
-@@ -1107,6 +1109,7 @@
- 	rcu_read_lock();
- 
- 	sta = tx.sta;
-+	tx.u.tx.mgmt_interface = mgmt;
- 	tx.u.tx.mode = local->hw.conf.mode;
- 
- 	for (handler = local->tx_handlers; *handler != NULL;
-@@ -1253,7 +1256,8 @@
- 		control.flags |= IEEE80211_TXCTL_REQUEUE;
- 	control.queue = pkt_data->queue;
- 
--	ret = ieee80211_tx(odev, skb, &control);
-+	ret = ieee80211_tx(odev, skb, &control,
-+			   control.type == IEEE80211_IF_TYPE_MGMT);
- 	dev_put(odev);
- 
- 	return ret;
-@@ -1498,6 +1502,8 @@
- 	pkt_data = (struct ieee80211_tx_packet_data *)skb->cb;
- 	memset(pkt_data, 0, sizeof(struct ieee80211_tx_packet_data));
- 	pkt_data->ifindex = dev->ifindex;
-+	if (sdata->type == IEEE80211_IF_TYPE_MGMT)
-+		pkt_data->flags |= IEEE80211_TXPD_MGMT_IFACE;
- 
- 	skb->dev = local->mdev;
- 	dev->stats.tx_packets++;
-@@ -1555,6 +1561,8 @@
- 	pkt_data = (struct ieee80211_tx_packet_data *) skb->cb;
- 	memset(pkt_data, 0, sizeof(struct ieee80211_tx_packet_data));
- 	pkt_data->ifindex = sdata->dev->ifindex;
-+	if (sdata->type == IEEE80211_IF_TYPE_MGMT)
-+		pkt_data->flags |= IEEE80211_TXPD_MGMT_IFACE;
- 
- 	skb->priority = 20; /* use hardcoded priority for mgmt TX queue */
- 	skb->dev = sdata->local->mdev;
-Index: mac80211/net/mac80211/wme.c
-===================================================================
---- mac80211.orig/net/mac80211/wme.c	2007-11-11 15:15:42.888038502 +0100
-+++ mac80211/net/mac80211/wme.c	2007-11-11 15:15:53.804660611 +0100
-@@ -94,6 +94,8 @@
- static inline int classify80211(struct sk_buff *skb, struct Qdisc *qd)
- {
- 	struct ieee80211_local *local = wdev_priv(qd->dev->ieee80211_ptr);
-+	struct ieee80211_tx_packet_data *pkt_data =
-+		(struct ieee80211_tx_packet_data *) skb->cb;
- 	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
- 	unsigned short fc = le16_to_cpu(hdr->frame_control);
- 	int qos;
-@@ -106,8 +108,12 @@
- 		return IEEE80211_TX_QUEUE_DATA0;
- 	}
- 
--	if (0 /* injected */) {
--		/* use AC from radiotap */
-+	if (unlikely(pkt_data->flags & IEEE80211_TXPD_MGMT_IFACE)) {
-+		/* Data frames from hostapd (mainly, EAPOL) use AC_VO
-+		* and they will include QoS control fields if
-+		* the target STA is using WME. */
-+		skb->priority = 7;
-+		return ieee802_1d_to_ac[skb->priority];
- 	}
- 
- 	/* is this a QoS frame? */
-Index: mac80211/net/mac80211/ieee80211_ioctl.c
-===================================================================
---- mac80211.orig/net/mac80211/ieee80211_ioctl.c	2007-11-11 15:15:51.532531127 +0100
-+++ mac80211/net/mac80211/ieee80211_ioctl.c	2007-11-11 15:15:53.808660833 +0100
-@@ -840,16 +840,29 @@
- 					void *wrqu, char *extra)
- {
- 	struct ieee80211_sub_if_data *sdata;
-+	struct ieee80211_local *local;
- 	int *i = (int *) extra;
- 	int param = *i;
-+	int value = *(i + 1);
- 	int ret = 0;
- 
- 	if (!capable(CAP_NET_ADMIN))
- 		return -EPERM;
- 
- 	sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-+	local = sdata->local;
- 
- 	switch (param) {
-+	case PRISM2_PARAM_MGMT_IF:
-+		if (value == 1) {
-+			if (!local->apdev)
-+				ret = ieee80211_if_add_mgmt(local);
-+		} else if (value == 0) {
-+			if (local->apdev)
-+				ieee80211_if_del_mgmt(local);
-+		} else
-+			ret = -EINVAL;
-+		break;
- 	default:
- 		ret = -EOPNOTSUPP;
- 		break;
-@@ -864,12 +877,20 @@
- 					    void *wrqu, char *extra)
- {
- 	struct ieee80211_sub_if_data *sdata;
-+	struct ieee80211_local *local;
- 	int *param = (int *) extra;
- 	int ret = 0;
- 
- 	sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-+	local = sdata->local;
- 
- 	switch (*param) {
-+	case PRISM2_PARAM_MGMT_IF:
-+		if (local->apdev)
-+			*param = local->apdev->ifindex;
-+		else
-+			ret = -ENOENT;
-+		break;
- 	default:
- 		ret = -EOPNOTSUPP;
- 		break;
diff --git a/package/mac80211/patches/011-allow-ap-vlan-modes.patch b/package/mac80211/patches/011-allow-ap-vlan-modes.patch
deleted file mode 100644
index d0edfe835c..0000000000
--- a/package/mac80211/patches/011-allow-ap-vlan-modes.patch
+++ /dev/null
@@ -1,37 +0,0 @@
-Subject: mac80211: allow AP and VLAN modes
-
-This adds AP/VLAN modes to the list of modes that a mac80211
-interface can be created in/switched into.
-
-Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
-
----
- net/mac80211/cfg.c             |    4 ++++
- net/mac80211/ieee80211_ioctl.c |    3 +++
- 2 files changed, 7 insertions(+)
-
---- everything.orig/net/mac80211/cfg.c	2007-10-30 15:33:43.227379286 +0100
-+++ everything/net/mac80211/cfg.c	2007-11-07 13:19:27.981515569 +0100
-@@ -25,6 +25,10 @@ nl80211_type_to_mac80211_type(enum nl802
- 		return IEEE80211_IF_TYPE_STA;
- 	case NL80211_IFTYPE_MONITOR:
- 		return IEEE80211_IF_TYPE_MNTR;
-+	case NL80211_IFTYPE_AP:
-+		return IEEE80211_IF_TYPE_AP;
-+	case NL80211_IFTYPE_AP_VLAN:
-+		return IEEE80211_IF_TYPE_VLAN;
- 	default:
- 		return IEEE80211_IF_TYPE_INVALID;
- 	}
---- everything.orig/net/mac80211/ieee80211_ioctl.c	2007-11-07 13:19:25.851524684 +0100
-+++ everything/net/mac80211/ieee80211_ioctl.c	2007-11-07 13:19:27.981515569 +0100
-@@ -284,6 +284,9 @@ static int ieee80211_ioctl_siwmode(struc
- 	case IW_MODE_MONITOR:
- 		type = IEEE80211_IF_TYPE_MNTR;
- 		break;
-+	case IW_MODE_MASTER:
-+		type = IEEE80211_IF_TYPE_AP;
-+		break;
- 	default:
- 		return -EINVAL;
- 	}
diff --git a/package/mac80211/patches/012-mac80211-allow-wds.patch b/package/mac80211/patches/012-mac80211-allow-wds.patch
deleted file mode 100644
index d5c57cd019..0000000000
--- a/package/mac80211/patches/012-mac80211-allow-wds.patch
+++ /dev/null
@@ -1,22 +0,0 @@
-Subject: mac80211: allow WDS mode
-
-This allows creating interfaces in WDS mode or switching
-existing ones into WDS mode (both via cfg80211.)
-
-Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
-
----
- net/mac80211/cfg.c |    2 ++
- 1 file changed, 2 insertions(+)
-
---- everything.orig/net/mac80211/cfg.c	2007-11-07 13:19:27.981515569 +0100
-+++ everything/net/mac80211/cfg.c	2007-11-07 13:19:29.441515732 +0100
-@@ -29,6 +29,8 @@ nl80211_type_to_mac80211_type(enum nl802
- 		return IEEE80211_IF_TYPE_AP;
- 	case NL80211_IFTYPE_AP_VLAN:
- 		return IEEE80211_IF_TYPE_VLAN;
-+	case NL80211_IFTYPE_WDS:
-+		return IEEE80211_IF_TYPE_WDS;
- 	default:
- 		return IEEE80211_IF_TYPE_INVALID;
- 	}
diff --git a/package/mac80211/patches/013-prism2-ioctl-bridge-packets.patch b/package/mac80211/patches/013-prism2-ioctl-bridge-packets.patch
deleted file mode 100644
index d418ad3497..0000000000
--- a/package/mac80211/patches/013-prism2-ioctl-bridge-packets.patch
+++ /dev/null
@@ -1,26 +0,0 @@
----
- net/mac80211/ieee80211_ioctl.c |    6 ++++++
- 1 file changed, 6 insertions(+)
-
---- everything.orig/net/mac80211/ieee80211_ioctl.c	2007-11-07 13:19:27.981515569 +0100
-+++ everything/net/mac80211/ieee80211_ioctl.c	2007-11-07 13:19:30.781513182 +0100
-@@ -882,6 +882,9 @@ static int ieee80211_ioctl_prism2_param(
- 	local = sdata->local;
- 
- 	switch (param) {
-+	case PRISM2_PARAM_AP_BRIDGE_PACKETS:
-+		local->bridge_packets = value;
-+		break;
- 	case PRISM2_PARAM_MGMT_IF:
- 		if (value == 1) {
- 			if (!local->apdev)
-@@ -914,6 +917,9 @@ static int ieee80211_ioctl_get_prism2_pa
- 	local = sdata->local;
- 
- 	switch (*param) {
-+	case PRISM2_PARAM_AP_BRIDGE_PACKETS:
-+		*param = local->bridge_packets;
-+		break;
- 	case PRISM2_PARAM_MGMT_IF:
- 		if (local->apdev)
- 			*param = local->apdev->ifindex;
diff --git a/package/mac80211/patches/014-prism2-ioctl-8021x.patch b/package/mac80211/patches/014-prism2-ioctl-8021x.patch
deleted file mode 100644
index 5feb01ea32..0000000000
--- a/package/mac80211/patches/014-prism2-ioctl-8021x.patch
+++ /dev/null
@@ -1,26 +0,0 @@
----
- net/mac80211/ieee80211_ioctl.c |    6 ++++++
- 1 file changed, 6 insertions(+)
-
---- everything.orig/net/mac80211/ieee80211_ioctl.c	2007-11-07 13:19:30.781513182 +0100
-+++ everything/net/mac80211/ieee80211_ioctl.c	2007-11-07 13:19:32.281514919 +0100
-@@ -882,6 +882,9 @@ static int ieee80211_ioctl_prism2_param(
- 	local = sdata->local;
- 
- 	switch (param) {
-+	case PRISM2_PARAM_IEEE_802_1X:
-+		sdata->ieee802_1x = value;
-+		break;
- 	case PRISM2_PARAM_AP_BRIDGE_PACKETS:
- 		local->bridge_packets = value;
- 		break;
-@@ -917,6 +920,9 @@ static int ieee80211_ioctl_get_prism2_pa
- 	local = sdata->local;
- 
- 	switch (*param) {
-+	case PRISM2_PARAM_IEEE_802_1X:
-+		*param = sdata->ieee802_1x;
-+		break;
- 	case PRISM2_PARAM_AP_BRIDGE_PACKETS:
- 		*param = local->bridge_packets;
- 		break;
diff --git a/package/mac80211/patches/015-hostapd-ioctl-hw-features.patch b/package/mac80211/patches/015-hostapd-ioctl-hw-features.patch
deleted file mode 100644
index d6e5dfd073..0000000000
--- a/package/mac80211/patches/015-hostapd-ioctl-hw-features.patch
+++ /dev/null
@@ -1,122 +0,0 @@
----
- net/mac80211/ieee80211_ioctl.c |  102 +++++++++++++++++++++++++++++++++++++++++
- 1 file changed, 102 insertions(+)
-
---- everything.orig/net/mac80211/ieee80211_ioctl.c	2007-11-07 13:19:32.281514919 +0100
-+++ everything/net/mac80211/ieee80211_ioctl.c	2007-11-07 13:19:33.681513453 +0100
-@@ -125,6 +125,105 @@ static int ieee80211_ioctl_siwgenie(stru
- 	return -EOPNOTSUPP;
- }
- 
-+/*
-+ * Wow. This ioctl interface is such crap, it's tied
-+ * to internal definitions. I hope it dies soon.
-+ */
-+static int mode_to_hostapd_mode(enum ieee80211_phymode mode)
-+{
-+	switch (mode) {
-+	case MODE_IEEE80211A:
-+		return 0;
-+	case MODE_IEEE80211B:
-+		return 1;
-+	case MODE_IEEE80211G:
-+		return 3;
-+	case NUM_IEEE80211_MODES:
-+		WARN_ON(1);
-+		break;
-+	}
-+	WARN_ON(1);
-+	return -1;
-+}
-+
-+static int channel_flags_to_hostapd_flags(int flags)
-+{
-+	int res = 0;
-+
-+	if (flags & IEEE80211_CHAN_W_SCAN)
-+		res |= 1;
-+	if (flags & IEEE80211_CHAN_W_ACTIVE_SCAN)
-+		res |= 2;
-+	if (flags & IEEE80211_CHAN_W_IBSS)
-+		res |= 4;
-+
-+	return res;
-+}
-+
-+struct ieee80211_channel_data {
-+	short chan; /* channel number (IEEE 802.11) */
-+	short freq; /* frequency in MHz */
-+	int flag; /* flag for hostapd use (IEEE80211_CHAN_*) */
-+};
-+
-+struct ieee80211_rate_data {
-+	int rate; /* rate in 100 kbps */
-+	int flags; /* IEEE80211_RATE_ flags */
-+};
-+
-+static int ieee80211_ioctl_get_hw_features(struct net_device *dev,
-+					   struct prism2_hostapd_param *param,
-+					   int param_len)
-+{
-+	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
-+	u8 *pos = param->u.hw_features.data;
-+	int left = param_len - (pos - (u8 *) param);
-+	int i;
-+	struct hostapd_ioctl_hw_modes_hdr *hdr;
-+	struct ieee80211_rate_data *rate;
-+	struct ieee80211_channel_data *chan;
-+	struct ieee80211_hw_mode *mode;
-+
-+	param->u.hw_features.flags = 0;
-+
-+	param->u.hw_features.num_modes = 0;
-+	list_for_each_entry(mode, &local->modes_list, list) {
-+		int clen, rlen;
-+
-+		param->u.hw_features.num_modes++;
-+		clen =
-+		    mode->num_channels * sizeof(struct ieee80211_channel_data);
-+		rlen = mode->num_rates * sizeof(struct ieee80211_rate_data);
-+		if (left < sizeof(*hdr) + clen + rlen)
-+			return -E2BIG;
-+		left -= sizeof(*hdr) + clen + rlen;
-+
-+		hdr = (struct hostapd_ioctl_hw_modes_hdr *)pos;
-+		hdr->mode = mode_to_hostapd_mode(mode->mode);
-+		hdr->num_channels = mode->num_channels;
-+		hdr->num_rates = mode->num_rates;
-+
-+		pos = (u8 *) (hdr + 1);
-+		chan = (struct ieee80211_channel_data *)pos;
-+		for (i = 0; i < mode->num_channels; i++) {
-+			chan[i].chan = mode->channels[i].chan;
-+			chan[i].freq = mode->channels[i].freq;
-+			chan[i].flag = channel_flags_to_hostapd_flags(
-+						mode->channels[i].flag);
-+		}
-+		pos += clen;
-+
-+		rate = (struct ieee80211_rate_data *)pos;
-+		for (i = 0; i < mode->num_rates; i++) {
-+			rate[i].rate = mode->rates[i].rate;
-+			rate[i].flags = mode->rates[i].flags;
-+		}
-+		pos += rlen;
-+	}
-+
-+	return 0;
-+}
-+
- 
- static int ieee80211_ioctl_priv_hostapd(struct net_device *dev,
- 					struct iw_point *p)
-@@ -151,6 +250,9 @@ static int ieee80211_ioctl_priv_hostapd(
- 	}
- 
- 	switch (param->cmd) {
-+	case PRISM2_HOSTAPD_GET_HW_FEATURES:
-+		ret = ieee80211_ioctl_get_hw_features(dev, param, p->length);
-+		break;
- 	default:
- 		ret = -EOPNOTSUPP;
- 		break;
diff --git a/package/mac80211/patches/016-prism2-ioctl-eapol.patch b/package/mac80211/patches/016-prism2-ioctl-eapol.patch
deleted file mode 100644
index 5ce57587ab..0000000000
--- a/package/mac80211/patches/016-prism2-ioctl-eapol.patch
+++ /dev/null
@@ -1,26 +0,0 @@
----
- net/mac80211/ieee80211_ioctl.c |    6 ++++++
- 1 file changed, 6 insertions(+)
-
---- everything.orig/net/mac80211/ieee80211_ioctl.c	2007-11-07 13:19:33.681513453 +0100
-+++ everything/net/mac80211/ieee80211_ioctl.c	2007-11-07 13:19:35.171517576 +0100
-@@ -984,6 +984,9 @@ static int ieee80211_ioctl_prism2_param(
- 	local = sdata->local;
- 
- 	switch (param) {
-+	case PRISM2_PARAM_EAPOL:
-+		sdata->eapol = value;
-+		break;
- 	case PRISM2_PARAM_IEEE_802_1X:
- 		sdata->ieee802_1x = value;
- 		break;
-@@ -1022,6 +1025,9 @@ static int ieee80211_ioctl_get_prism2_pa
- 	local = sdata->local;
- 
- 	switch (*param) {
-+	case PRISM2_PARAM_EAPOL:
-+		*param = sdata->eapol;
-+		break;
- 	case PRISM2_PARAM_IEEE_802_1X:
- 		*param = sdata->ieee802_1x;
- 		break;
diff --git a/package/mac80211/patches/017-nl80211-add-key-mgmt.patch b/package/mac80211/patches/017-nl80211-add-key-mgmt.patch
deleted file mode 100644
index f5b1d45c15..0000000000
--- a/package/mac80211/patches/017-nl80211-add-key-mgmt.patch
+++ /dev/null
@@ -1,470 +0,0 @@
-Subject: cfg80211/nl80211: introduce key handling
-
-This introduces key handling to cfg80211/nl80211. Default
-and group keys can be added, changed and removed; sequence
-counters for each key can be retrieved.
-
-Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
-
----
- include/linux/nl80211.h |   34 +++++
- include/net/cfg80211.h  |   44 +++++++
- net/wireless/core.c     |    3 
- net/wireless/nl80211.c  |  289 ++++++++++++++++++++++++++++++++++++++++++++++++
- 4 files changed, 370 insertions(+)
-
---- everything.orig/include/linux/nl80211.h	2007-10-30 15:33:43.587381346 +0100
-+++ everything/include/linux/nl80211.h	2007-11-07 13:19:37.861516599 +0100
-@@ -37,6 +37,16 @@
-  *	userspace to request deletion of a virtual interface, then requires
-  *	attribute %NL80211_ATTR_IFINDEX.
-  *
-+ * @NL80211_CMD_GET_KEY: Get sequence counter information for a key specified
-+ *	by %NL80211_ATTR_KEY_IDX and/or %NL80211_ATTR_MAC.
-+ * @NL80211_CMD_SET_KEY: Set key attributes %NL80211_ATTR_KEY_DEFAULT or
-+ *	%NL80211_ATTR_KEY_THRESHOLD.
-+ * @NL80211_CMD_NEW_KEY: add a key with given %NL80211_ATTR_KEY_DATA,
-+ *	%NL80211_ATTR_KEY_IDX, %NL80211_ATTR_MAC and %NL80211_ATTR_KEY_CIPHER
-+ *	attributes.
-+ * @NL80211_CMD_DEL_KEY: delete a key identified by %NL80211_ATTR_KEY_IDX
-+ *	or %NL80211_ATTR_MAC.
-+ *
-  * @NL80211_CMD_MAX: highest used command number
-  * @__NL80211_CMD_AFTER_LAST: internal use
-  */
-@@ -54,6 +64,11 @@ enum nl80211_commands {
- 	NL80211_CMD_NEW_INTERFACE,
- 	NL80211_CMD_DEL_INTERFACE,
- 
-+	NL80211_CMD_GET_KEY,
-+	NL80211_CMD_SET_KEY,
-+	NL80211_CMD_NEW_KEY,
-+	NL80211_CMD_DEL_KEY,
-+
- 	/* add commands here */
- 
- 	/* used to define NL80211_CMD_MAX below */
-@@ -75,6 +90,17 @@ enum nl80211_commands {
-  * @NL80211_ATTR_IFNAME: network interface name
-  * @NL80211_ATTR_IFTYPE: type of virtual interface, see &enum nl80211_iftype
-  *
-+ * @NL80211_ATTR_MAC: MAC address (various uses)
-+ *
-+ * @NL80211_ATTR_KEY_DATA: (temporal) key data; for TKIP this consists of
-+ *	16 bytes encryption key followed by 8 bytes each for TX and RX MIC
-+ *	keys
-+ * @NL80211_ATTR_KEY_IDX: key ID (u8, 0-3)
-+ * @NL80211_ATTR_KEY_CIPHER: key cipher suite (u32, as defined by IEEE 802.11
-+ *	section 7.3.2.25.1, e.g. 0x000FAC04)
-+ * @NL80211_ATTR_KEY_SEQ: transmit key sequence number (IV/PN) for TKIP and
-+ *	CCMP keys, each six bytes in little endian
-+ *
-  * @NL80211_ATTR_MAX: highest attribute number currently defined
-  * @__NL80211_ATTR_AFTER_LAST: internal use
-  */
-@@ -89,6 +115,14 @@ enum nl80211_attrs {
- 	NL80211_ATTR_IFNAME,
- 	NL80211_ATTR_IFTYPE,
- 
-+	NL80211_ATTR_MAC,
-+
-+	NL80211_ATTR_KEY_DATA,
-+	NL80211_ATTR_KEY_IDX,
-+	NL80211_ATTR_KEY_CIPHER,
-+	NL80211_ATTR_KEY_SEQ,
-+	NL80211_ATTR_KEY_DEFAULT,
-+
- 	/* add attributes here, update the policy in nl80211.c */
- 
- 	__NL80211_ATTR_AFTER_LAST,
---- everything.orig/net/wireless/nl80211.c	2007-10-30 15:33:43.637380153 +0100
-+++ everything/net/wireless/nl80211.c	2007-11-07 13:19:38.201511066 +0100
-@@ -61,6 +61,14 @@ static struct nla_policy nl80211_policy[
- 	[NL80211_ATTR_IFTYPE] = { .type = NLA_U32 },
- 	[NL80211_ATTR_IFINDEX] = { .type = NLA_U32 },
- 	[NL80211_ATTR_IFNAME] = { .type = NLA_NUL_STRING, .len = IFNAMSIZ-1 },
-+
-+	[NL80211_ATTR_MAC] = { .type = NLA_BINARY, .len = ETH_ALEN },
-+
-+	[NL80211_ATTR_KEY_DATA] = { .type = NLA_BINARY,
-+				    .len = WLAN_MAX_KEY_LEN },
-+	[NL80211_ATTR_KEY_IDX] = { .type = NLA_U8 },
-+	[NL80211_ATTR_KEY_CIPHER] = { .type = NLA_U32 },
-+	[NL80211_ATTR_KEY_DEFAULT] = { .type = NLA_FLAG },
- };
- 
- /* message building helper */
-@@ -335,6 +343,263 @@ static int nl80211_del_interface(struct 
- 	return err;
- }
- 
-+struct get_key_cookie {
-+	struct sk_buff *msg;
-+	int error;
-+};
-+
-+static void get_key_callback(void *c, struct key_params *params)
-+{
-+	struct get_key_cookie *cookie = c;
-+
-+	if (params->key)
-+		NLA_PUT(cookie->msg, NL80211_ATTR_KEY_DATA,
-+			params->key_len, params->key);
-+
-+	if (params->seq)
-+		NLA_PUT(cookie->msg, NL80211_ATTR_KEY_SEQ,
-+			params->seq_len, params->seq);
-+
-+	if (params->cipher)
-+		NLA_PUT_U32(cookie->msg, NL80211_ATTR_KEY_CIPHER,
-+			    params->cipher);
-+
-+	return;
-+ nla_put_failure:
-+	cookie->error = 1;
-+}
-+
-+static int nl80211_get_key(struct sk_buff *skb, struct genl_info *info)
-+{
-+	struct cfg80211_registered_device *drv;
-+	int err;
-+	struct net_device *dev;
-+	u8 key_idx = 0;
-+	u8 *mac_addr = NULL;
-+	struct get_key_cookie cookie = {
-+		.error = 0,
-+	};
-+	void *hdr;
-+	struct sk_buff *msg;
-+
-+	if (info->attrs[NL80211_ATTR_KEY_IDX])
-+		key_idx = nla_get_u8(info->attrs[NL80211_ATTR_KEY_IDX]);
-+
-+	if (key_idx > 3)
-+		return -EINVAL;
-+
-+	if (info->attrs[NL80211_ATTR_MAC])
-+		mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
-+
-+	err = get_drv_dev_by_info_ifindex(info, &drv, &dev);
-+	if (err)
-+		return err;
-+
-+	if (!drv->ops->get_key) {
-+		err = -EOPNOTSUPP;
-+		goto out;
-+	}
-+
-+	msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
-+	if (!msg) {
-+		err = -ENOMEM;
-+		goto out;
-+	}
-+
-+	hdr = nl80211hdr_put(msg, info->snd_pid, info->snd_seq, 0,
-+			     NL80211_CMD_NEW_KEY);
-+
-+	if (IS_ERR(hdr)) {
-+		err = PTR_ERR(hdr);
-+		goto out;
-+	}
-+
-+	cookie.msg = msg;
-+
-+	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, dev->ifindex);
-+	NLA_PUT_U8(msg, NL80211_ATTR_KEY_IDX, key_idx);
-+	if (mac_addr)
-+		NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, mac_addr);
-+
-+	rtnl_lock();
-+	err = drv->ops->get_key(&drv->wiphy, dev, key_idx, mac_addr,
-+				&cookie, get_key_callback);
-+	rtnl_unlock();
-+
-+	if (err)
-+		goto out;
-+
-+	if (cookie.error)
-+		goto nla_put_failure;
-+
-+	genlmsg_end(msg, hdr);
-+	err = genlmsg_unicast(msg, info->snd_pid);
-+	goto out;
-+
-+ nla_put_failure:
-+	err = -ENOBUFS;
-+	nlmsg_free(msg);
-+ out:
-+	cfg80211_put_dev(drv);
-+	dev_put(dev);
-+	return err;
-+}
-+
-+static int nl80211_set_key(struct sk_buff *skb, struct genl_info *info)
-+{
-+	struct cfg80211_registered_device *drv;
-+	int err;
-+	struct net_device *dev;
-+	u8 key_idx;
-+
-+	if (!info->attrs[NL80211_ATTR_KEY_IDX])
-+		return -EINVAL;
-+
-+	key_idx = nla_get_u8(info->attrs[NL80211_ATTR_KEY_IDX]);
-+
-+	if (key_idx > 3)
-+		return -EINVAL;
-+
-+	/* currently only support setting default key */
-+	if (!info->attrs[NL80211_ATTR_KEY_DEFAULT])
-+		return -EINVAL;
-+
-+	err = get_drv_dev_by_info_ifindex(info, &drv, &dev);
-+	if (err)
-+		return err;
-+
-+	if (!drv->ops->set_default_key) {
-+		err = -EOPNOTSUPP;
-+		goto out;
-+	}
-+
-+	rtnl_lock();
-+	err = drv->ops->set_default_key(&drv->wiphy, dev, key_idx);
-+	rtnl_unlock();
-+
-+ out:
-+	cfg80211_put_dev(drv);
-+	dev_put(dev);
-+	return err;
-+}
-+
-+static int nl80211_new_key(struct sk_buff *skb, struct genl_info *info)
-+{
-+	struct cfg80211_registered_device *drv;
-+	int err;
-+	struct net_device *dev;
-+	struct key_params params;
-+	u8 key_idx = 0;
-+	u8 *mac_addr = NULL;
-+
-+	memset(&params, 0, sizeof(params));
-+
-+	if (!info->attrs[NL80211_ATTR_KEY_CIPHER])
-+		return -EINVAL;
-+
-+	if (info->attrs[NL80211_ATTR_KEY_DATA]) {
-+		params.key = nla_data(info->attrs[NL80211_ATTR_KEY_DATA]);
-+		params.key_len = nla_len(info->attrs[NL80211_ATTR_KEY_DATA]);
-+	}
-+
-+	if (info->attrs[NL80211_ATTR_KEY_IDX])
-+		key_idx = nla_get_u8(info->attrs[NL80211_ATTR_KEY_IDX]);
-+
-+	params.cipher = nla_get_u32(info->attrs[NL80211_ATTR_KEY_CIPHER]);
-+
-+	if (info->attrs[NL80211_ATTR_MAC])
-+		mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
-+
-+	if (key_idx > 3)
-+		return -EINVAL;
-+
-+	/*
-+	 * Disallow pairwise keys with non-zero index unless it's WEP
-+	 * (because current deployments use pairwise WEP keys with
-+	 * non-zero indizes but 802.11i clearly specifies to use zero)
-+	 */
-+	if (mac_addr && key_idx &&
-+	    params.cipher != WLAN_CIPHER_SUITE_WEP40 &&
-+	    params.cipher != WLAN_CIPHER_SUITE_WEP104)
-+		return -EINVAL;
-+
-+	/* TODO: add definitions for the lengths to linux/ieee80211.h */
-+	switch (params.cipher) {
-+	case WLAN_CIPHER_SUITE_WEP40:
-+		if (params.key_len != 5)
-+			return -EINVAL;
-+		break;
-+	case WLAN_CIPHER_SUITE_TKIP:
-+		if (params.key_len != 32)
-+			return -EINVAL;
-+		break;
-+	case WLAN_CIPHER_SUITE_CCMP:
-+		if (params.key_len != 16)
-+			return -EINVAL;
-+		break;
-+	case WLAN_CIPHER_SUITE_WEP104:
-+		if (params.key_len != 13)
-+			return -EINVAL;
-+		break;
-+	default:
-+		return -EINVAL;
-+	}
-+
-+	err = get_drv_dev_by_info_ifindex(info, &drv, &dev);
-+	if (err)
-+		return err;
-+
-+	if (!drv->ops->add_key) {
-+		err = -EOPNOTSUPP;
-+		goto out;
-+	}
-+
-+	rtnl_lock();
-+	err = drv->ops->add_key(&drv->wiphy, dev, key_idx, mac_addr, &params);
-+	rtnl_unlock();
-+
-+ out:
-+	cfg80211_put_dev(drv);
-+	dev_put(dev);
-+	return err;
-+}
-+
-+static int nl80211_del_key(struct sk_buff *skb, struct genl_info *info)
-+{
-+	struct cfg80211_registered_device *drv;
-+	int err;
-+	struct net_device *dev;
-+	u8 key_idx = 0;
-+	u8 *mac_addr = NULL;
-+
-+	if (info->attrs[NL80211_ATTR_KEY_IDX])
-+		key_idx = nla_get_u8(info->attrs[NL80211_ATTR_KEY_IDX]);
-+
-+	if (key_idx > 3)
-+		return -EINVAL;
-+
-+	if (info->attrs[NL80211_ATTR_MAC])
-+		mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
-+
-+	err = get_drv_dev_by_info_ifindex(info, &drv, &dev);
-+	if (err)
-+		return err;
-+
-+	if (!drv->ops->del_key) {
-+		err = -EOPNOTSUPP;
-+		goto out;
-+	}
-+
-+	rtnl_lock();
-+	err = drv->ops->del_key(&drv->wiphy, dev, key_idx, mac_addr);
-+	rtnl_unlock();
-+
-+ out:
-+	cfg80211_put_dev(drv);
-+	dev_put(dev);
-+	return err;
-+}
-+
- static struct genl_ops nl80211_ops[] = {
- 	{
- 		.cmd = NL80211_CMD_GET_WIPHY,
-@@ -374,6 +639,30 @@ static struct genl_ops nl80211_ops[] = {
- 		.policy = nl80211_policy,
- 		.flags = GENL_ADMIN_PERM,
- 	},
-+	{
-+		.cmd = NL80211_CMD_GET_KEY,
-+		.doit = nl80211_get_key,
-+		.policy = nl80211_policy,
-+		.flags = GENL_ADMIN_PERM,
-+	},
-+	{
-+		.cmd = NL80211_CMD_SET_KEY,
-+		.doit = nl80211_set_key,
-+		.policy = nl80211_policy,
-+		.flags = GENL_ADMIN_PERM,
-+	},
-+	{
-+		.cmd = NL80211_CMD_NEW_KEY,
-+		.doit = nl80211_new_key,
-+		.policy = nl80211_policy,
-+		.flags = GENL_ADMIN_PERM,
-+	},
-+	{
-+		.cmd = NL80211_CMD_DEL_KEY,
-+		.doit = nl80211_del_key,
-+		.policy = nl80211_policy,
-+		.flags = GENL_ADMIN_PERM,
-+	},
- };
- 
- /* multicast groups */
---- everything.orig/net/wireless/core.c	2007-10-30 15:33:43.677380478 +0100
-+++ everything/net/wireless/core.c	2007-11-07 13:19:38.221513833 +0100
-@@ -184,6 +184,9 @@ struct wiphy *wiphy_new(struct cfg80211_
- 	struct cfg80211_registered_device *drv;
- 	int alloc_size;
- 
-+	WARN_ON(!ops->add_key && ops->del_key);
-+	WARN_ON(ops->add_key && !ops->del_key);
-+
- 	alloc_size = sizeof(*drv) + sizeof_priv;
- 
- 	drv = kzalloc(alloc_size, GFP_KERNEL);
---- everything.orig/include/net/cfg80211.h	2007-10-30 15:33:43.617381780 +0100
-+++ everything/include/net/cfg80211.h	2007-11-07 13:19:38.231512748 +0100
-@@ -49,6 +49,26 @@ extern int ieee80211_radiotap_iterator_n
-    struct ieee80211_radiotap_iterator *iterator);
- 
- 
-+ /**
-+ * struct key_params - key information
-+ *
-+ * Information about a key
-+ *
-+ * @key: key material
-+ * @key_len: length of key material
-+ * @cipher: cipher suite selector
-+ * @seq: sequence counter (IV/PN) for TKIP and CCMP keys, only used
-+ *	with the get_key() callback, must be in little endian,
-+ *	length given by @seq_len.
-+ */
-+struct key_params {
-+	u8 *key;
-+	u8 *seq;
-+	int key_len;
-+	int seq_len;
-+	u32 cipher;
-+};
-+
- /* from net/wireless.h */
- struct wiphy;
- 
-@@ -71,6 +91,18 @@ struct wiphy;
-  *
-  * @change_virtual_intf: change type of virtual interface
-  *
-+ * @add_key: add a key with the given parameters. @mac_addr will be %NULL
-+ *	when adding a group key.
-+ *
-+ * @get_key: get information about the key with the given parameters.
-+ *	@mac_addr will be %NULL when requesting information for a group
-+ *	key. All pointers given to the @callback function need not be valid
-+ *	after it returns.
-+ *
-+ * @del_key: remove a key given the @mac_addr (%NULL for a group key)
-+ *	and @key_index
-+ *
-+ * @set_default_key: set the default key on an interface
-  */
- struct cfg80211_ops {
- 	int	(*add_virtual_intf)(struct wiphy *wiphy, char *name,
-@@ -78,6 +110,18 @@ struct cfg80211_ops {
- 	int	(*del_virtual_intf)(struct wiphy *wiphy, int ifindex);
- 	int	(*change_virtual_intf)(struct wiphy *wiphy, int ifindex,
- 				       enum nl80211_iftype type);
-+
-+	int	(*add_key)(struct wiphy *wiphy, struct net_device *netdev,
-+			   u8 key_index, u8 *mac_addr,
-+			   struct key_params *params);
-+	int	(*get_key)(struct wiphy *wiphy, struct net_device *netdev,
-+			   u8 key_index, u8 *mac_addr, void *cookie,
-+			   void (*callback)(void *cookie, struct key_params*));
-+	int	(*del_key)(struct wiphy *wiphy, struct net_device *netdev,
-+			   u8 key_index, u8 *mac_addr);
-+	int	(*set_default_key)(struct wiphy *wiphy,
-+				   struct net_device *netdev,
-+				   u8 key_index);
- };
- 
- #endif /* __NET_CFG80211_H */
diff --git a/package/mac80211/patches/018-mac80211-cfg80211-keys.patch b/package/mac80211/patches/018-mac80211-cfg80211-keys.patch
deleted file mode 100644
index 0c98623a2d..0000000000
--- a/package/mac80211/patches/018-mac80211-cfg80211-keys.patch
+++ /dev/null
@@ -1,120 +0,0 @@
-Subject: mac80211: support adding/removing keys via cfg80211
-
-This adds the necessary hooks to mac80211 to allow userspace
-to edit keys with cfg80211 (through nl80211.)
-
-Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
-
----
- net/mac80211/cfg.c |   91 +++++++++++++++++++++++++++++++++++++++++++++++++++++
- 1 file changed, 91 insertions(+)
-
---- everything.orig/net/mac80211/cfg.c	2007-11-07 13:19:29.441515732 +0100
-+++ everything/net/mac80211/cfg.c	2007-11-07 13:19:39.531517685 +0100
-@@ -6,6 +6,7 @@
-  * This file is GPLv2 as found in COPYING.
-  */
- 
-+#include <linux/ieee80211.h>
- #include <linux/nl80211.h>
- #include <linux/rtnetlink.h>
- #include <net/net_namespace.h>
-@@ -105,8 +106,98 @@ static int ieee80211_change_iface(struct
- 	return 0;
- }
- 
-+static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev,
-+			     u8 key_idx, u8 *mac_addr,
-+			     struct key_params *params)
-+{
-+	struct ieee80211_sub_if_data *sdata;
-+	struct sta_info *sta = NULL;
-+	enum ieee80211_key_alg alg;
-+	int ret;
-+
-+	sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-+
-+	switch (params->cipher) {
-+	case WLAN_CIPHER_SUITE_WEP40:
-+	case WLAN_CIPHER_SUITE_WEP104:
-+		alg = ALG_WEP;
-+		break;
-+	case WLAN_CIPHER_SUITE_TKIP:
-+		alg = ALG_TKIP;
-+		break;
-+	case WLAN_CIPHER_SUITE_CCMP:
-+		alg = ALG_CCMP;
-+		break;
-+	default:
-+		return -EINVAL;
-+	}
-+
-+	if (mac_addr) {
-+		sta = sta_info_get(sdata->local, mac_addr);
-+		if (!sta)
-+			return -ENOENT;
-+	}
-+
-+	ret = 0;
-+	if (!ieee80211_key_alloc(sdata, sta, alg, key_idx,
-+				 params->key_len, params->key))
-+		ret = -ENOMEM;
-+
-+	if (sta)
-+		sta_info_put(sta);
-+
-+	return ret;
-+}
-+
-+static int ieee80211_del_key(struct wiphy *wiphy, struct net_device *dev,
-+			     u8 key_idx, u8 *mac_addr)
-+{
-+	struct ieee80211_sub_if_data *sdata;
-+	struct sta_info *sta;
-+	int ret;
-+
-+	sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-+
-+	if (mac_addr) {
-+		sta = sta_info_get(sdata->local, mac_addr);
-+		if (!sta)
-+			return -ENOENT;
-+
-+		ret = 0;
-+		if (sta->key)
-+			ieee80211_key_free(sta->key);
-+		else
-+			ret = -ENOENT;
-+
-+		sta_info_put(sta);
-+		return ret;
-+	}
-+
-+	if (!sdata->keys[key_idx])
-+		return -ENOENT;
-+
-+	ieee80211_key_free(sdata->keys[key_idx]);
-+
-+	return 0;
-+}
-+
-+static int ieee80211_config_default_key(struct wiphy *wiphy,
-+					struct net_device *dev,
-+					u8 key_idx)
-+{
-+	struct ieee80211_sub_if_data *sdata;
-+
-+	sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-+	ieee80211_set_default_key(sdata, key_idx);
-+
-+	return 0;
-+}
-+
- struct cfg80211_ops mac80211_config_ops = {
- 	.add_virtual_intf = ieee80211_add_iface,
- 	.del_virtual_intf = ieee80211_del_iface,
- 	.change_virtual_intf = ieee80211_change_iface,
-+	.add_key = ieee80211_add_key,
-+	.del_key = ieee80211_del_key,
-+	.set_default_key = ieee80211_config_default_key,
- };
diff --git a/package/mac80211/patches/019-mac80211-key-seq-nl80211.patch b/package/mac80211/patches/019-mac80211-key-seq-nl80211.patch
deleted file mode 100644
index 5d0020b7fe..0000000000
--- a/package/mac80211/patches/019-mac80211-key-seq-nl80211.patch
+++ /dev/null
@@ -1,161 +0,0 @@
-Subject: mac80211: support getting key sequence counters via cfg80211
-
-This implements cfg80211's get_key() to allow retrieving the sequence
-counter for a TKIP or CCMP key from userspace. It also cleans up and
-documents the associated low-level driver interface.
-
-Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
-
----
- include/net/mac80211.h |   14 ++------
- net/mac80211/cfg.c     |   85 ++++++++++++++++++++++++++++++++++++++++++++++++-
- 2 files changed, 89 insertions(+), 10 deletions(-)
-
-Index: mac80211/net/mac80211/cfg.c
-===================================================================
---- mac80211.orig/net/mac80211/cfg.c	2007-11-11 15:46:41.497954646 +0100
-+++ mac80211/net/mac80211/cfg.c	2007-11-11 15:46:51.346515884 +0100
-@@ -1,7 +1,7 @@
- /*
-  * mac80211 configuration hooks for cfg80211
-  *
-- * Copyright 2006	Johannes Berg <johannes@sipsolutions.net>
-+ * Copyright 2006, 2007	Johannes Berg <johannes@sipsolutions.net>
-  *
-  * This file is GPLv2 as found in COPYING.
-  */
-@@ -180,6 +180,88 @@
- 	return 0;
- }
- 
-+static int ieee80211_get_key(struct wiphy *wiphy, struct net_device *dev,
-+			     u8 key_idx, u8 *mac_addr, void *cookie,
-+			     void (*callback)(void *cookie,
-+					      struct key_params *params))
-+{
-+	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-+	struct sta_info *sta = NULL;
-+	u8 seq[6] = {0};
-+	struct key_params params;
-+	struct ieee80211_key *key;
-+	u32 iv32;
-+	u16 iv16;
-+	int err = -ENOENT;
-+
-+	if (mac_addr) {
-+		sta = sta_info_get(sdata->local, mac_addr);
-+		if (!sta)
-+			goto out;
-+
-+		key = sta->key;
-+	} else
-+		key = sdata->keys[key_idx];
-+
-+	if (!key)
-+		goto out;
-+
-+	memset(&params, 0, sizeof(params));
-+
-+	switch (key->conf.alg) {
-+	case ALG_TKIP:
-+		params.cipher = WLAN_CIPHER_SUITE_TKIP;
-+
-+		iv32 = key->u.tkip.iv32;
-+		iv16 = key->u.tkip.iv16;
-+
-+		if (key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE &&
-+		    sdata->local->ops->get_tkip_seq)
-+			sdata->local->ops->get_tkip_seq(
-+				local_to_hw(sdata->local),
-+				key->conf.hw_key_idx,
-+				&iv32, &iv16);
-+
-+		seq[0] = iv16 & 0xff;
-+		seq[1] = (iv16 >> 8) & 0xff;
-+		seq[2] = iv32 & 0xff;
-+		seq[3] = (iv32 >> 8) & 0xff;
-+		seq[4] = (iv32 >> 16) & 0xff;
-+		seq[5] = (iv32 >> 24) & 0xff;
-+		params.seq = seq;
-+		params.seq_len = 6;
-+		break;
-+	case ALG_CCMP:
-+		params.cipher = WLAN_CIPHER_SUITE_CCMP;
-+		seq[0] = key->u.ccmp.tx_pn[5];
-+		seq[1] = key->u.ccmp.tx_pn[4];
-+		seq[2] = key->u.ccmp.tx_pn[3];
-+		seq[3] = key->u.ccmp.tx_pn[2];
-+		seq[4] = key->u.ccmp.tx_pn[1];
-+		seq[5] = key->u.ccmp.tx_pn[0];
-+		params.seq = seq;
-+		params.seq_len = 6;
-+		break;
-+	case ALG_WEP:
-+		if (key->conf.keylen == 5)
-+			params.cipher = WLAN_CIPHER_SUITE_WEP40;
-+		else
-+			params.cipher = WLAN_CIPHER_SUITE_WEP104;
-+		break;
-+	}
-+
-+	params.key = key->conf.key;
-+	params.key_len = key->conf.keylen;
-+
-+	callback(cookie, &params);
-+	err = 0;
-+
-+ out:
-+	if (sta)
-+		sta_info_put(sta);
-+	return err;
-+}
-+
- static int ieee80211_config_default_key(struct wiphy *wiphy,
- 					struct net_device *dev,
- 					u8 key_idx)
-@@ -198,5 +280,6 @@
- 	.change_virtual_intf = ieee80211_change_iface,
- 	.add_key = ieee80211_add_key,
- 	.del_key = ieee80211_del_key,
-+	.get_key = ieee80211_get_key,
- 	.set_default_key = ieee80211_config_default_key,
- };
-Index: mac80211/include/net/mac80211.h
-===================================================================
---- mac80211.orig/include/net/mac80211.h	2007-11-11 15:46:41.377947807 +0100
-+++ mac80211/include/net/mac80211.h	2007-11-11 15:47:08.183475366 +0100
-@@ -598,9 +598,6 @@
- 	u8 key[0];
- };
- 
--#define IEEE80211_SEQ_COUNTER_RX	0
--#define IEEE80211_SEQ_COUNTER_TX	1
--
- /**
-  * enum set_key_cmd - key command
-  *
-@@ -947,9 +944,9 @@
-  *
-  * @get_stats: return low-level statistics
-  *
-- * @get_sequence_counter: For devices that have internal sequence counters this
-- *	callback allows mac80211 to access the current value of a counter.
-- *	This callback seems not well-defined, tell us if you need it.
-+ * @get_tkip_seq: If your device implements TKIP encryption in hardware this
-+ *	callback should be provided to read the TKIP transmit IVs (both IV32
-+ *	and IV16) for the given key from hardware.
-  *
-  * @set_rts_threshold: Configuration of RTS threshold (if device needs it)
-  *
-@@ -1022,9 +1019,8 @@
- 	int (*hw_scan)(struct ieee80211_hw *hw, u8 *ssid, size_t len);
- 	int (*get_stats)(struct ieee80211_hw *hw,
- 			 struct ieee80211_low_level_stats *stats);
--	int (*get_sequence_counter)(struct ieee80211_hw *hw,
--				    u8* addr, u8 keyidx, u8 txrx,
--				    u32* iv32, u16* iv16);
-+	void (*get_tkip_seq)(struct ieee80211_hw *hw, u8 hw_key_idx,
-+			     u32 *iv32, u16 *iv16);
- 	int (*set_rts_threshold)(struct ieee80211_hw *hw, u32 value);
- 	int (*set_frag_threshold)(struct ieee80211_hw *hw, u32 value);
- 	int (*set_retry_limit)(struct ieee80211_hw *hw,
diff --git a/package/mac80211/patches/020-nl80211-beacon-parameters.patch b/package/mac80211/patches/020-nl80211-beacon-parameters.patch
deleted file mode 100644
index 51836f332f..0000000000
--- a/package/mac80211/patches/020-nl80211-beacon-parameters.patch
+++ /dev/null
@@ -1,279 +0,0 @@
-Subject: cfg80211/nl80211: add beacon settings
-
-This adds the necessary API to cfg80211/nl80211 to allow
-changing beaconing settings.
-
-Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
-
----
- include/linux/nl80211.h |   24 ++++++++
- include/net/cfg80211.h  |   33 +++++++++++
- net/wireless/nl80211.c  |  133 ++++++++++++++++++++++++++++++++++++++++++++++++
- 3 files changed, 190 insertions(+)
-
---- everything.orig/include/net/cfg80211.h	2007-11-08 11:50:57.412840007 +0100
-+++ everything/include/net/cfg80211.h	2007-11-08 16:50:38.421522842 +0100
-@@ -69,6 +69,26 @@ struct key_params {
- 	u32 cipher;
- };
- 
-+/**
-+ * struct beacon_parameters - beacon parameters
-+ *
-+ * Used to configure the beacon for an interface.
-+ *
-+ * @head: head portion of beacon (before TIM IE)
-+ *     or %NULL if not changed
-+ * @tail: tail portion of beacon (after TIM IE)
-+ *     or %NULL if not changed
-+ * @interval: beacon interval or zero if not changed
-+ * @dtim_period: DTIM period or zero if not changed
-+ * @head_len: length of @head
-+ * @tail_len: length of @tail
-+ */
-+struct beacon_parameters {
-+	u8 *head, *tail;
-+	int interval, dtim_period;
-+	int head_len, tail_len;
-+};
-+
- /* from net/wireless.h */
- struct wiphy;
- 
-@@ -103,6 +123,13 @@ struct wiphy;
-  *	and @key_index
-  *
-  * @set_default_key: set the default key on an interface
-+ *
-+ * @add_beacon: Add a beacon with given parameters, @head, @interval
-+ *	and @dtim_period will be valid, @tail is optional.
-+ * @set_beacon: Change the beacon parameters for an access point mode
-+ *	interface. This should reject the call when no beacon has been
-+ *	configured.
-+ * @del_beacon: Remove beacon configuration and stop sending the beacon.
-  */
- struct cfg80211_ops {
- 	int	(*add_virtual_intf)(struct wiphy *wiphy, char *name,
-@@ -122,6 +149,12 @@ struct cfg80211_ops {
- 	int	(*set_default_key)(struct wiphy *wiphy,
- 				   struct net_device *netdev,
- 				   u8 key_index);
-+
-+	int	(*add_beacon)(struct wiphy *wiphy, struct net_device *dev,
-+			      struct beacon_parameters *info);
-+	int	(*set_beacon)(struct wiphy *wiphy, struct net_device *dev,
-+			      struct beacon_parameters *info);
-+	int	(*del_beacon)(struct wiphy *wiphy, struct net_device *dev);
- };
- 
- #endif /* __NET_CFG80211_H */
---- everything.orig/include/linux/nl80211.h	2007-11-08 11:50:57.362839952 +0100
-+++ everything/include/linux/nl80211.h	2007-11-08 16:56:32.431522732 +0100
-@@ -47,6 +47,15 @@
-  * @NL80211_CMD_DEL_KEY: delete a key identified by %NL80211_ATTR_KEY_IDX
-  *	or %NL80211_ATTR_MAC.
-  *
-+ * @NL80211_CMD_GET_BEACON: retrieve beacon information (returned in a
-+ *	%NL80222_CMD_NEW_BEACON message)
-+ * @NL80211_CMD_SET_BEACON: set the beacon on an access point interface
-+ *	using the %NL80211_ATTR_BEACON_INTERVAL, %NL80211_ATTR_DTIM_PERIOD,
-+ *	%NL80211_BEACON_HEAD and %NL80211_BEACON_TAIL attributes.
-+ * @NL80211_CMD_NEW_BEACON: add a new beacon to an access point interface,
-+ *	parameters are like for %NL80211_CMD_SET_BEACON.
-+ * @NL80211_CMD_DEL_BEACON: remove the beacon, stop sending it
-+ *
-  * @NL80211_CMD_MAX: highest used command number
-  * @__NL80211_CMD_AFTER_LAST: internal use
-  */
-@@ -69,6 +78,11 @@ enum nl80211_commands {
- 	NL80211_CMD_NEW_KEY,
- 	NL80211_CMD_DEL_KEY,
- 
-+	NL80211_CMD_GET_BEACON,
-+	NL80211_CMD_SET_BEACON,
-+	NL80211_CMD_NEW_BEACON,
-+	NL80211_CMD_DEL_BEACON,
-+
- 	/* add commands here */
- 
- 	/* used to define NL80211_CMD_MAX below */
-@@ -101,6 +115,11 @@ enum nl80211_commands {
-  * @NL80211_ATTR_KEY_SEQ: transmit key sequence number (IV/PN) for TKIP and
-  *	CCMP keys, each six bytes in little endian
-  *
-+ * @NL80211_ATTR_BEACON_INTERVAL: beacon interval in TU
-+ * @NL80211_ATTR_DTIM_PERIOD: DTIM period for beaconing
-+ * @NL80211_ATTR_BEACON_HEAD: portion of the beacon before the TIM IE
-+ * @NL80211_ATTR_BEACON_TAIL: portion of the beacon after the TIM IE
-+ *
-  * @NL80211_ATTR_MAX: highest attribute number currently defined
-  * @__NL80211_ATTR_AFTER_LAST: internal use
-  */
-@@ -123,6 +142,11 @@ enum nl80211_attrs {
- 	NL80211_ATTR_KEY_SEQ,
- 	NL80211_ATTR_KEY_DEFAULT,
- 
-+	NL80211_ATTR_BEACON_INTERVAL,
-+	NL80211_ATTR_DTIM_PERIOD,
-+	NL80211_ATTR_BEACON_HEAD,
-+	NL80211_ATTR_BEACON_TAIL,
-+
- 	/* add attributes here, update the policy in nl80211.c */
- 
- 	__NL80211_ATTR_AFTER_LAST,
---- everything.orig/net/wireless/nl80211.c	2007-11-08 11:50:57.382836589 +0100
-+++ everything/net/wireless/nl80211.c	2007-11-08 16:58:36.711524524 +0100
-@@ -69,6 +69,13 @@ static struct nla_policy nl80211_policy[
- 	[NL80211_ATTR_KEY_IDX] = { .type = NLA_U8 },
- 	[NL80211_ATTR_KEY_CIPHER] = { .type = NLA_U32 },
- 	[NL80211_ATTR_KEY_DEFAULT] = { .type = NLA_FLAG },
-+
-+	[NL80211_ATTR_BEACON_INTERVAL] = { .type = NLA_U32 },
-+	[NL80211_ATTR_DTIM_PERIOD] = { .type = NLA_U32 },
-+	[NL80211_ATTR_BEACON_HEAD] = { .type = NLA_BINARY,
-+				       .len = IEEE80211_MAX_DATA_LEN },
-+	[NL80211_ATTR_BEACON_TAIL] = { .type = NLA_BINARY,
-+				       .len = IEEE80211_MAX_DATA_LEN },
- };
- 
- /* message building helper */
-@@ -600,6 +607,114 @@ static int nl80211_del_key(struct sk_buf
- 	return err;
- }
- 
-+static int nl80211_addset_beacon(struct sk_buff *skb, struct genl_info *info)
-+{
-+        int (*call)(struct wiphy *wiphy, struct net_device *dev,
-+		    struct beacon_parameters *info);
-+	struct cfg80211_registered_device *drv;
-+	int err;
-+	struct net_device *dev;
-+	struct beacon_parameters params;
-+	int haveinfo = 0;
-+
-+	err = get_drv_dev_by_info_ifindex(info, &drv, &dev);
-+	if (err)
-+		return err;
-+
-+	switch (info->genlhdr->cmd) {
-+	case NL80211_CMD_NEW_BEACON:
-+		/* these are required for NEW_BEACON */
-+		if (!info->attrs[NL80211_ATTR_BEACON_INTERVAL] ||
-+		    !info->attrs[NL80211_ATTR_DTIM_PERIOD] ||
-+		    !info->attrs[NL80211_ATTR_BEACON_HEAD]) {
-+			err = -EINVAL;
-+			goto out;
-+		}
-+
-+		call = drv->ops->add_beacon;
-+		break;
-+	case NL80211_CMD_SET_BEACON:
-+		call = drv->ops->set_beacon;
-+		break;
-+	default:
-+		WARN_ON(1);
-+		err = -EOPNOTSUPP;
-+		goto out;
-+	}
-+
-+	if (!call) {
-+		err = -EOPNOTSUPP;
-+		goto out;
-+	}
-+
-+	memset(&params, 0, sizeof(params));
-+
-+	if (info->attrs[NL80211_ATTR_BEACON_INTERVAL]) {
-+		params.interval =
-+		    nla_get_u32(info->attrs[NL80211_ATTR_BEACON_INTERVAL]);
-+		haveinfo = 1;
-+	}
-+
-+	if (info->attrs[NL80211_ATTR_DTIM_PERIOD]) {
-+		params.dtim_period =
-+		    nla_get_u32(info->attrs[NL80211_ATTR_DTIM_PERIOD]);
-+		haveinfo = 1;
-+	}
-+
-+	if (info->attrs[NL80211_ATTR_BEACON_HEAD]) {
-+		params.head = nla_data(info->attrs[NL80211_ATTR_BEACON_HEAD]);
-+		params.head_len =
-+		    nla_len(info->attrs[NL80211_ATTR_BEACON_HEAD]);
-+		haveinfo = 1;
-+	}
-+
-+	if (info->attrs[NL80211_ATTR_BEACON_TAIL]) {
-+		params.tail = nla_data(info->attrs[NL80211_ATTR_BEACON_TAIL]);
-+		params.tail_len =
-+		    nla_len(info->attrs[NL80211_ATTR_BEACON_TAIL]);
-+		haveinfo = 1;
-+	}
-+
-+	if (!haveinfo) {
-+		err = -EINVAL;
-+		goto out;
-+	}
-+
-+	rtnl_lock();
-+	err = call(&drv->wiphy, dev, &params);
-+	rtnl_unlock();
-+
-+ out:
-+	cfg80211_put_dev(drv);
-+	dev_put(dev);
-+	return err;
-+}
-+
-+static int nl80211_del_beacon(struct sk_buff *skb, struct genl_info *info)
-+{
-+	struct cfg80211_registered_device *drv;
-+	int err;
-+	struct net_device *dev;
-+
-+	err = get_drv_dev_by_info_ifindex(info, &drv, &dev);
-+	if (err)
-+		return err;
-+
-+	if (!drv->ops->del_beacon) {
-+		err = -EOPNOTSUPP;
-+		goto out;
-+	}
-+
-+	rtnl_lock();
-+	err = drv->ops->del_beacon(&drv->wiphy, dev);
-+	rtnl_unlock();
-+
-+ out:
-+	cfg80211_put_dev(drv);
-+	dev_put(dev);
-+	return err;
-+}
-+
- static struct genl_ops nl80211_ops[] = {
- 	{
- 		.cmd = NL80211_CMD_GET_WIPHY,
-@@ -663,6 +778,24 @@ static struct genl_ops nl80211_ops[] = {
- 		.policy = nl80211_policy,
- 		.flags = GENL_ADMIN_PERM,
- 	},
-+	{
-+		.cmd = NL80211_CMD_SET_BEACON,
-+		.policy = nl80211_policy,
-+		.flags = GENL_ADMIN_PERM,
-+		.doit = nl80211_addset_beacon,
-+	},
-+	{
-+		.cmd = NL80211_CMD_NEW_BEACON,
-+		.policy = nl80211_policy,
-+		.flags = GENL_ADMIN_PERM,
-+		.doit = nl80211_addset_beacon,
-+	},
-+	{
-+		.cmd = NL80211_CMD_DEL_BEACON,
-+		.policy = nl80211_policy,
-+		.flags = GENL_ADMIN_PERM,
-+		.doit = nl80211_del_beacon,
-+	},
- };
- 
- /* multicast groups */
diff --git a/package/mac80211/patches/021-mac80211-beacon-via-nl80211.patch b/package/mac80211/patches/021-mac80211-beacon-via-nl80211.patch
deleted file mode 100644
index 702c68f98f..0000000000
--- a/package/mac80211/patches/021-mac80211-beacon-via-nl80211.patch
+++ /dev/null
@@ -1,484 +0,0 @@
-Subject: mac80211: add beacon configuration via cfg80211
-
-This patch implements the cfg80211 hooks for configuring beaconing
-on an access point interface in mac80211. While doing so, it fixes
-a number of races that could badly crash the machine when the
-beacon is changed while being requested by the driver.
-
-Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
-
----
-The dtim_count field should possibly also be part of the beacon
-structure, but the possible race there doesn't really matter,
-worst thing is that one beacon will be sent with a wrong dtim
-count if (and only if) userspace changes the dtim period during
-operation.
-
- net/mac80211/cfg.c             |  156 +++++++++++++++++++++++++++++++++++++++++
- net/mac80211/debugfs_netdev.c  |   27 -------
- net/mac80211/ieee80211_i.h     |   14 ++-
- net/mac80211/ieee80211_iface.c |    4 -
- net/mac80211/tx.c              |   63 ++++++++++------
- 5 files changed, 204 insertions(+), 60 deletions(-)
-
-Index: mac80211/net/mac80211/cfg.c
-===================================================================
---- mac80211.orig/net/mac80211/cfg.c	2007-11-11 15:17:12.837164411 +0100
-+++ mac80211/net/mac80211/cfg.c	2007-11-11 15:18:36.853952256 +0100
-@@ -9,6 +9,7 @@
- #include <linux/ieee80211.h>
- #include <linux/nl80211.h>
- #include <linux/rtnetlink.h>
-+#include <linux/rcupdate.h>
- #include <net/cfg80211.h>
- #include "ieee80211_i.h"
- #include "cfg.h"
-@@ -274,6 +275,158 @@
- 	return 0;
- }
- 
-+/*
-+ * This handles both adding a beacon and setting new beacon info
-+ */
-+static int ieee80211_config_beacon(struct ieee80211_sub_if_data *sdata,
-+				   struct beacon_parameters *params)
-+{
-+	struct beacon_data *new, *old;
-+	int new_head_len, new_tail_len;
-+	int size;
-+	int err = -EINVAL;
-+
-+	old = sdata->u.ap.beacon;
-+
-+	/* head must not be zero-length */
-+	if (params->head && !params->head_len)
-+		return -EINVAL;
-+
-+	/*
-+	 * This is a kludge. beacon interval should really be part
-+	 * of the beacon information.
-+	 */
-+	if (params->interval) {
-+		sdata->local->hw.conf.beacon_int = params->interval;
-+		if (ieee80211_hw_config(sdata->local))
-+			return -EINVAL;
-+		/*
-+		 * We updated some parameter so if below bails out
-+		 * it's not an error.
-+		 */
-+		err = 0;
-+	}
-+
-+	/* Need to have a beacon head if we don't have one yet */
-+	if (!params->head && !old)
-+		return err;
-+
-+	/* sorry, no way to start beaconing without dtim period */
-+	if (!params->dtim_period && !old)
-+		return err;
-+
-+	/* new or old head? */
-+	if (params->head)
-+		new_head_len = params->head_len;
-+	else
-+		new_head_len = old->head_len;
-+
-+	/* new or old tail? */
-+	if (params->tail || !old)
-+		/* params->tail_len will be zero for !params->tail */
-+		new_tail_len = params->tail_len;
-+	else
-+		new_tail_len = old->tail_len;
-+
-+	size = sizeof(*new) + new_head_len + new_tail_len;
-+
-+	new = kzalloc(size, GFP_KERNEL);
-+	if (!new)
-+		return -ENOMEM;
-+
-+	/* start filling the new info now */
-+
-+	/* new or old dtim period? */
-+	if (params->dtim_period)
-+		new->dtim_period = params->dtim_period;
-+	else
-+		new->dtim_period = old->dtim_period;
-+
-+	/*
-+	 * pointers go into the block we allocated,
-+	 * memory is | beacon_data | head | tail |
-+	 */
-+	new->head = ((u8 *) new) + sizeof(*new);
-+	new->tail = new->head + new_head_len;
-+	new->head_len = new_head_len;
-+	new->tail_len = new_tail_len;
-+
-+	/* copy in head */
-+	if (params->head)
-+		memcpy(new->head, params->head, new_head_len);
-+	else
-+		memcpy(new->head, old->head, new_head_len);
-+
-+	/* copy in optional tail */
-+	if (params->tail)
-+		memcpy(new->tail, params->tail, new_tail_len);
-+	else
-+		if (old)
-+			memcpy(new->tail, old->tail, new_tail_len);
-+
-+	rcu_assign_pointer(sdata->u.ap.beacon, new);
-+
-+	synchronize_rcu();
-+
-+	kfree(old);
-+
-+	return ieee80211_if_config_beacon(sdata->dev);
-+}
-+
-+static int ieee80211_add_beacon(struct wiphy *wiphy, struct net_device *dev,
-+				struct beacon_parameters *params)
-+{
-+	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-+	struct beacon_data *old;
-+
-+	if (sdata->type != IEEE80211_IF_TYPE_AP)
-+		return -EINVAL;
-+
-+	old = sdata->u.ap.beacon;
-+
-+	if (old)
-+		return -EALREADY;
-+
-+	return ieee80211_config_beacon(sdata, params);
-+}
-+
-+static int ieee80211_set_beacon(struct wiphy *wiphy, struct net_device *dev,
-+				struct beacon_parameters *params)
-+{
-+	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-+	struct beacon_data *old;
-+
-+	if (sdata->type != IEEE80211_IF_TYPE_AP)
-+		return -EINVAL;
-+
-+	old = sdata->u.ap.beacon;
-+
-+	if (!old)
-+		return -ENOENT;
-+
-+	return ieee80211_config_beacon(sdata, params);
-+}
-+
-+static int ieee80211_del_beacon(struct wiphy *wiphy, struct net_device *dev)
-+{
-+	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-+	struct beacon_data *old;
-+
-+	if (sdata->type != IEEE80211_IF_TYPE_AP)
-+		return -EINVAL;
-+
-+	old = sdata->u.ap.beacon;
-+
-+	if (!old)
-+		return -ENOENT;
-+
-+	rcu_assign_pointer(sdata->u.ap.beacon, NULL);
-+	synchronize_rcu();
-+	kfree(old);
-+
-+	return ieee80211_if_config_beacon(dev);
-+}
-+
- struct cfg80211_ops mac80211_config_ops = {
- 	.add_virtual_intf = ieee80211_add_iface,
- 	.del_virtual_intf = ieee80211_del_iface,
-@@ -282,4 +435,7 @@
- 	.del_key = ieee80211_del_key,
- 	.get_key = ieee80211_get_key,
- 	.set_default_key = ieee80211_config_default_key,
-+	.add_beacon = ieee80211_add_beacon,
-+	.set_beacon = ieee80211_set_beacon,
-+	.del_beacon = ieee80211_del_beacon,
- };
-Index: mac80211/net/mac80211/debugfs_netdev.c
-===================================================================
---- mac80211.orig/net/mac80211/debugfs_netdev.c	2007-10-14 00:42:30.054156000 +0200
-+++ mac80211/net/mac80211/debugfs_netdev.c	2007-11-11 15:18:11.852527505 +0100
-@@ -124,7 +124,6 @@
- 
- /* AP attributes */
- IEEE80211_IF_FILE(num_sta_ps, u.ap.num_sta_ps, ATOMIC);
--IEEE80211_IF_FILE(dtim_period, u.ap.dtim_period, DEC);
- IEEE80211_IF_FILE(dtim_count, u.ap.dtim_count, DEC);
- IEEE80211_IF_FILE(num_beacons, u.ap.num_beacons, DEC);
- IEEE80211_IF_FILE(force_unicast_rateidx, u.ap.force_unicast_rateidx, DEC);
-@@ -138,26 +137,6 @@
- }
- __IEEE80211_IF_FILE(num_buffered_multicast);
- 
--static ssize_t ieee80211_if_fmt_beacon_head_len(
--	const struct ieee80211_sub_if_data *sdata, char *buf, int buflen)
--{
--	if (sdata->u.ap.beacon_head)
--		return scnprintf(buf, buflen, "%d\n",
--				 sdata->u.ap.beacon_head_len);
--	return scnprintf(buf, buflen, "\n");
--}
--__IEEE80211_IF_FILE(beacon_head_len);
--
--static ssize_t ieee80211_if_fmt_beacon_tail_len(
--	const struct ieee80211_sub_if_data *sdata, char *buf, int buflen)
--{
--	if (sdata->u.ap.beacon_tail)
--		return scnprintf(buf, buflen, "%d\n",
--				 sdata->u.ap.beacon_tail_len);
--	return scnprintf(buf, buflen, "\n");
--}
--__IEEE80211_IF_FILE(beacon_tail_len);
--
- /* WDS attributes */
- IEEE80211_IF_FILE(peer, u.wds.remote_addr, MAC);
- 
-@@ -194,14 +173,11 @@
- 	DEBUGFS_ADD(eapol, ap);
- 	DEBUGFS_ADD(ieee8021_x, ap);
- 	DEBUGFS_ADD(num_sta_ps, ap);
--	DEBUGFS_ADD(dtim_period, ap);
- 	DEBUGFS_ADD(dtim_count, ap);
- 	DEBUGFS_ADD(num_beacons, ap);
- 	DEBUGFS_ADD(force_unicast_rateidx, ap);
- 	DEBUGFS_ADD(max_ratectrl_rateidx, ap);
- 	DEBUGFS_ADD(num_buffered_multicast, ap);
--	DEBUGFS_ADD(beacon_head_len, ap);
--	DEBUGFS_ADD(beacon_tail_len, ap);
- }
- 
- static void add_wds_files(struct ieee80211_sub_if_data *sdata)
-@@ -287,14 +263,11 @@
- 	DEBUGFS_DEL(eapol, ap);
- 	DEBUGFS_DEL(ieee8021_x, ap);
- 	DEBUGFS_DEL(num_sta_ps, ap);
--	DEBUGFS_DEL(dtim_period, ap);
- 	DEBUGFS_DEL(dtim_count, ap);
- 	DEBUGFS_DEL(num_beacons, ap);
- 	DEBUGFS_DEL(force_unicast_rateidx, ap);
- 	DEBUGFS_DEL(max_ratectrl_rateidx, ap);
- 	DEBUGFS_DEL(num_buffered_multicast, ap);
--	DEBUGFS_DEL(beacon_head_len, ap);
--	DEBUGFS_DEL(beacon_tail_len, ap);
- }
- 
- static void del_wds_files(struct ieee80211_sub_if_data *sdata)
-Index: mac80211/net/mac80211/ieee80211_i.h
-===================================================================
---- mac80211.orig/net/mac80211/ieee80211_i.h	2007-11-11 15:15:53.792659922 +0100
-+++ mac80211/net/mac80211/ieee80211_i.h	2007-11-11 15:18:11.864528190 +0100
-@@ -190,9 +190,14 @@
- typedef ieee80211_txrx_result (*ieee80211_rx_handler)
- (struct ieee80211_txrx_data *rx);
- 
-+struct beacon_data {
-+	u8 *head, *tail;
-+	int head_len, tail_len;
-+	int dtim_period;
-+};
-+
- struct ieee80211_if_ap {
--	u8 *beacon_head, *beacon_tail;
--	int beacon_head_len, beacon_tail_len;
-+	struct beacon_data *beacon;
- 
- 	struct list_head vlans;
- 
-@@ -205,7 +210,7 @@
- 	u8 tim[sizeof(unsigned long) * BITS_TO_LONGS(IEEE80211_MAX_AID + 1)];
- 	atomic_t num_sta_ps; /* number of stations in PS mode */
- 	struct sk_buff_head ps_bc_buf;
--	int dtim_period, dtim_count;
-+	int dtim_count;
- 	int force_unicast_rateidx; /* forced TX rateidx for unicast frames */
- 	int max_ratectrl_rateidx; /* max TX rateidx for rate control */
- 	int num_beacons; /* number of TXed beacon frames for this BSS */
-@@ -361,14 +366,11 @@
- 			struct dentry *eapol;
- 			struct dentry *ieee8021_x;
- 			struct dentry *num_sta_ps;
--			struct dentry *dtim_period;
- 			struct dentry *dtim_count;
- 			struct dentry *num_beacons;
- 			struct dentry *force_unicast_rateidx;
- 			struct dentry *max_ratectrl_rateidx;
- 			struct dentry *num_buffered_multicast;
--			struct dentry *beacon_head_len;
--			struct dentry *beacon_tail_len;
- 		} ap;
- 		struct {
- 			struct dentry *channel_use;
-Index: mac80211/net/mac80211/ieee80211_iface.c
-===================================================================
---- mac80211.orig/net/mac80211/ieee80211_iface.c	2007-11-11 15:15:53.796660158 +0100
-+++ mac80211/net/mac80211/ieee80211_iface.c	2007-11-11 15:18:11.868528415 +0100
-@@ -187,7 +187,6 @@
- 		sdata->u.vlan.ap = NULL;
- 		break;
- 	case IEEE80211_IF_TYPE_AP:
--		sdata->u.ap.dtim_period = 2;
- 		sdata->u.ap.force_unicast_rateidx = -1;
- 		sdata->u.ap.max_ratectrl_rateidx = -1;
- 		skb_queue_head_init(&sdata->u.ap.ps_bc_buf);
-@@ -271,8 +270,7 @@
- 			}
- 		}
- 
--		kfree(sdata->u.ap.beacon_head);
--		kfree(sdata->u.ap.beacon_tail);
-+		kfree(sdata->u.ap.beacon);
- 
- 		while ((skb = skb_dequeue(&sdata->u.ap.ps_bc_buf))) {
- 			local->total_ps_buffered--;
-Index: mac80211/net/mac80211/tx.c
-===================================================================
---- mac80211.orig/net/mac80211/tx.c	2007-11-11 15:15:53.804660611 +0100
-+++ mac80211/net/mac80211/tx.c	2007-11-11 15:18:11.868528415 +0100
-@@ -1656,7 +1656,8 @@
- 
- static void ieee80211_beacon_add_tim(struct ieee80211_local *local,
- 				     struct ieee80211_if_ap *bss,
--				     struct sk_buff *skb)
-+				     struct sk_buff *skb,
-+				     struct beacon_data *beacon)
- {
- 	u8 *pos, *tim;
- 	int aid0 = 0;
-@@ -1672,7 +1673,7 @@
- 					  IEEE80211_MAX_AID+1);
- 
- 	if (bss->dtim_count == 0)
--		bss->dtim_count = bss->dtim_period - 1;
-+		bss->dtim_count = beacon->dtim_period - 1;
- 	else
- 		bss->dtim_count--;
- 
-@@ -1680,7 +1681,7 @@
- 	*pos++ = WLAN_EID_TIM;
- 	*pos++ = 4;
- 	*pos++ = bss->dtim_count;
--	*pos++ = bss->dtim_period;
-+	*pos++ = beacon->dtim_period;
- 
- 	if (bss->dtim_count == 0 && !skb_queue_empty(&bss->ps_bc_buf))
- 		aid0 = 1;
-@@ -1728,8 +1729,9 @@
- 	struct ieee80211_if_ap *ap = NULL;
- 	struct ieee80211_rate *rate;
- 	struct rate_control_extra extra;
--	u8 *b_head, *b_tail;
--	int bh_len, bt_len;
-+	struct beacon_data *beacon;
-+
-+	rcu_read_lock();
- 
- 	bdev = dev_get_by_index(if_id);
- 	if (bdev) {
-@@ -1738,37 +1740,35 @@
- 		dev_put(bdev);
- 	}
- 
--	if (!ap || sdata->type != IEEE80211_IF_TYPE_AP ||
--	    !ap->beacon_head) {
-+	beacon = rcu_dereference(ap->beacon);
-+
-+	if (!ap || sdata->type != IEEE80211_IF_TYPE_AP || !beacon) {
- #ifdef CONFIG_MAC80211_VERBOSE_DEBUG
- 		if (net_ratelimit())
- 			printk(KERN_DEBUG "no beacon data avail for idx=%d "
- 			       "(%s)\n", if_id, bdev ? bdev->name : "N/A");
- #endif /* CONFIG_MAC80211_VERBOSE_DEBUG */
--		return NULL;
-+		skb = NULL;
-+		goto out;
- 	}
- 
--	/* Assume we are generating the normal beacon locally */
--	b_head = ap->beacon_head;
--	b_tail = ap->beacon_tail;
--	bh_len = ap->beacon_head_len;
--	bt_len = ap->beacon_tail_len;
--
--	skb = dev_alloc_skb(local->tx_headroom +
--		bh_len + bt_len + 256 /* maximum TIM len */);
-+	/* headroom, head length, tail length and maximum TIM length */
-+	skb = dev_alloc_skb(local->tx_headroom + beacon->head_len +
-+			    beacon->tail_len + 256);
- 	if (!skb)
--		return NULL;
-+		goto out;
- 
- 	skb_reserve(skb, local->tx_headroom);
--	memcpy(skb_put(skb, bh_len), b_head, bh_len);
-+	memcpy(skb_put(skb, beacon->head_len), beacon->head,
-+	       beacon->head_len);
- 
- 	ieee80211_include_sequence(sdata, (struct ieee80211_hdr *)skb->data);
- 
--	ieee80211_beacon_add_tim(local, ap, skb);
-+	ieee80211_beacon_add_tim(local, ap, skb, beacon);
- 
--	if (b_tail) {
--		memcpy(skb_put(skb, bt_len), b_tail, bt_len);
--	}
-+	if (beacon->tail)
-+		memcpy(skb_put(skb, beacon->tail_len), beacon->tail,
-+		       beacon->tail_len);
- 
- 	if (control) {
- 		memset(&extra, 0, sizeof(extra));
-@@ -1781,7 +1781,8 @@
- 				       "found\n", wiphy_name(local->hw.wiphy));
- 			}
- 			dev_kfree_skb(skb);
--			return NULL;
-+			skb = NULL;
-+			goto out;
- 		}
- 
- 		control->tx_rate =
-@@ -1796,6 +1797,9 @@
- 	}
- 
- 	ap->num_beacons++;
-+
-+ out:
-+	rcu_read_unlock();
- 	return skb;
- }
- EXPORT_SYMBOL(ieee80211_beacon_get);
-@@ -1844,6 +1848,7 @@
- 	struct net_device *bdev;
- 	struct ieee80211_sub_if_data *sdata;
- 	struct ieee80211_if_ap *bss = NULL;
-+	struct beacon_data *beacon;
- 
- 	bdev = dev_get_by_index(if_id);
- 	if (bdev) {
-@@ -1851,9 +1856,19 @@
- 		bss = &sdata->u.ap;
- 		dev_put(bdev);
- 	}
--	if (!bss || sdata->type != IEEE80211_IF_TYPE_AP || !bss->beacon_head)
-+
-+	if (!bss)
- 		return NULL;
- 
-+	rcu_read_lock();
-+	beacon = rcu_dereference(bss->beacon);
-+
-+	if (sdata->type != IEEE80211_IF_TYPE_AP || !beacon || !beacon->head) {
-+		rcu_read_unlock();
-+		return NULL;
-+	}
-+	rcu_read_unlock();
-+
- 	if (bss->dtim_count != 0)
- 		return NULL; /* send buffered bc/mc only after DTIM beacon */
- 	memset(control, 0, sizeof(*control));
diff --git a/package/mac80211/patches/022-nl80211-sta.patch b/package/mac80211/patches/022-nl80211-sta.patch
deleted file mode 100644
index 4d08721f82..0000000000
--- a/package/mac80211/patches/022-nl80211-sta.patch
+++ /dev/null
@@ -1,464 +0,0 @@
-Subject: cfg80211/nl80211: station handling
-
-This patch adds station handling to cfg80211/nl80211.
-
-Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
-
----
- include/linux/nl80211.h |   68 +++++++++++++
- include/net/cfg80211.h  |   54 ++++++++++
- net/wireless/nl80211.c  |  236 ++++++++++++++++++++++++++++++++++++++++++++++++
- 3 files changed, 358 insertions(+)
-
---- everything.orig/include/linux/nl80211.h	2007-11-08 16:56:32.431522732 +0100
-+++ everything/include/linux/nl80211.h	2007-11-08 17:15:15.961529840 +0100
-@@ -7,6 +7,18 @@
-  */
- 
- /**
-+ * DOC: Station handling
-+ *
-+ * Stations are added per interface, but a special case exists with VLAN
-+ * interfaces. When a station is bound to an AP interface, it may be moved
-+ * into a VLAN identified by a VLAN interface index (%NL80211_ATTR_STA_VLAN).
-+ * The station is still assumed to belong to the AP interface it was added
-+ * to.
-+ *
-+ * TODO: need more info?
-+ */
-+
-+/**
-  * enum nl80211_commands - supported nl80211 commands
-  *
-  * @NL80211_CMD_UNSPEC: unspecified command to catch errors
-@@ -56,6 +68,16 @@
-  *	parameters are like for %NL80211_CMD_SET_BEACON.
-  * @NL80211_CMD_DEL_BEACON: remove the beacon, stop sending it
-  *
-+ * @NL80211_CMD_GET_STATION: Get station attributes for station identified by
-+ *	%NL80211_ATTR_MAC on the interface identified by %NL80211_ATTR_IFINDEX.
-+ * @NL80211_CMD_SET_STATION: Set station attributes for station identified by
-+ *	%NL80211_ATTR_MAC on the interface identified by %NL80211_ATTR_IFINDEX.
-+ * @NL80211_CMD_NEW_STATION: Add a station with given attributes to the
-+ *	the interface identified by %NL80211_ATTR_IFINDEX.
-+ * @NL80211_CMD_DEL_STATION: Remove a station identified by %NL80211_ATTR_MAC
-+ *	or, if no MAC address given, all stations, on the interface identified
-+ *	by %NL80211_ATTR_IFINDEX.
-+ *
-  * @NL80211_CMD_MAX: highest used command number
-  * @__NL80211_CMD_AFTER_LAST: internal use
-  */
-@@ -83,6 +105,11 @@ enum nl80211_commands {
- 	NL80211_CMD_NEW_BEACON,
- 	NL80211_CMD_DEL_BEACON,
- 
-+	NL80211_CMD_GET_STATION,
-+	NL80211_CMD_SET_STATION,
-+	NL80211_CMD_NEW_STATION,
-+	NL80211_CMD_DEL_STATION,
-+
- 	/* add commands here */
- 
- 	/* used to define NL80211_CMD_MAX below */
-@@ -120,6 +147,17 @@ enum nl80211_commands {
-  * @NL80211_ATTR_BEACON_HEAD: portion of the beacon before the TIM IE
-  * @NL80211_ATTR_BEACON_TAIL: portion of the beacon after the TIM IE
-  *
-+ * @NL80211_ATTR_STA_AID: Association ID for the station (u16)
-+ * @NL80211_ATTR_STA_FLAGS: flags, nested element with NLA_FLAG attributes of
-+ *	&enum nl80211_sta_flags.
-+ * @NL80211_ATTR_STA_LISTEN_INTERVAL: listen interval as defined by
-+ *	IEEE 802.11 7.3.1.6 (u16).
-+ * @NL80211_ATTR_STA_SUPPORTED_RATES: supported rates, array of supported
-+ *	rates as defined by IEEE 802.11 7.3.2.2 but without the length
-+ *	restriction (at most %NL80211_MAX_SUPP_RATES).
-+ * @NL80211_ATTR_STA_VLAN: interface index of VLAN interface to move station
-+ *	to, or the AP interface the station was originally added to to.
-+ *
-  * @NL80211_ATTR_MAX: highest attribute number currently defined
-  * @__NL80211_ATTR_AFTER_LAST: internal use
-  */
-@@ -147,12 +185,20 @@ enum nl80211_attrs {
- 	NL80211_ATTR_BEACON_HEAD,
- 	NL80211_ATTR_BEACON_TAIL,
- 
-+	NL80211_ATTR_STA_AID,
-+	NL80211_ATTR_STA_FLAGS,
-+	NL80211_ATTR_STA_LISTEN_INTERVAL,
-+	NL80211_ATTR_STA_SUPPORTED_RATES,
-+	NL80211_ATTR_STA_VLAN,
-+
- 	/* add attributes here, update the policy in nl80211.c */
- 
- 	__NL80211_ATTR_AFTER_LAST,
- 	NL80211_ATTR_MAX = __NL80211_ATTR_AFTER_LAST - 1
- };
- 
-+#define NL80211_MAX_SUPP_RATES	32
-+
- /**
-  * enum nl80211_iftype - (virtual) interface types
-  *
-@@ -184,4 +230,26 @@ enum nl80211_iftype {
- 	NL80211_IFTYPE_MAX = __NL80211_IFTYPE_AFTER_LAST - 1
- };
- 
-+/**
-+ * enum nl80211_sta_flags - station flags
-+ *
-+ * Station flags. When a station is added to an AP interface, it is
-+ * assumed to be already associated (and hence authenticated.)
-+ *
-+ * @NL80211_STA_FLAG_AUTHORIZED: station is authorized (802.1X)
-+ * @NL80211_STA_FLAG_SHORT_PREAMBLE: station is capable of receiving frames
-+ *	with short barker preamble
-+ * @NL80211_STA_FLAG_WME: station is WME/QoS capable
-+ */
-+enum nl80211_sta_flags {
-+	__NL80211_STA_FLAG_INVALID,
-+	NL80211_STA_FLAG_AUTHORIZED,
-+	NL80211_STA_FLAG_SHORT_PREAMBLE,
-+	NL80211_STA_FLAG_WME,
-+
-+	/* keep last */
-+	__NL80211_STA_FLAG_AFTER_LAST,
-+	NL80211_STA_FLAG_MAX = __NL80211_STA_FLAG_AFTER_LAST - 1
-+};
-+
- #endif /* __LINUX_NL80211_H */
---- everything.orig/include/net/cfg80211.h	2007-11-08 16:50:38.421522842 +0100
-+++ everything/include/net/cfg80211.h	2007-11-08 17:15:15.971532444 +0100
-@@ -89,6 +89,47 @@ struct beacon_parameters {
- 	int head_len, tail_len;
- };
- 
-+/**
-+ * enum station_flags - station flags
-+ *
-+ * Station capability flags. Note that these must be the bits
-+ * according to the nl80211 flags.
-+ *
-+ * @STATION_FLAG_CHANGED: station flags were changed
-+ * @STATION_FLAG_AUTHORIZED: station is authorized to send frames (802.1X)
-+ * @STATION_FLAG_SHORT_PREAMBLE: station is capable of receiving frames
-+ *	with short preambles
-+ * @STATION_FLAG_WME: station is WME/QoS capable
-+ */
-+enum station_flags {
-+	STATION_FLAG_CHANGED		= 1<<0,
-+	STATION_FLAG_AUTHORIZED		= 1<<NL80211_STA_FLAG_AUTHORIZED,
-+	STATION_FLAG_SHORT_PREAMBLE	= 1<<NL80211_STA_FLAG_SHORT_PREAMBLE,
-+	STATION_FLAG_WME		= 1<<NL80211_STA_FLAG_WME,
-+};
-+
-+/**
-+ * struct station_parameters - station parameters
-+ *
-+ * Used to change and create a new station.
-+ *
-+ * @vlan: vlan interface station should belong to
-+ * @supported_rates: supported rates in IEEE 802.11 format
-+ *	(or NULL for no change)
-+ * @supported_rates_len: number of supported rates
-+ * @station_flags: station flags (see &enum station_flags)
-+ * @listen_interval: listen interval or -1 for no change
-+ * @aid: AID or zero for no change
-+ */
-+struct station_parameters {
-+	u8 *supported_rates;
-+	struct net_device *vlan;
-+	u32 station_flags;
-+	int listen_interval;
-+	u16 aid;
-+	u8 supported_rates_len;
-+};
-+
- /* from net/wireless.h */
- struct wiphy;
- 
-@@ -130,6 +171,12 @@ struct wiphy;
-  *	interface. This should reject the call when no beacon has been
-  *	configured.
-  * @del_beacon: Remove beacon configuration and stop sending the beacon.
-+ *
-+ * @add_station: Add a new station.
-+ *
-+ * @del_station: Remove a station; @mac may be NULL to remove all stations.
-+ *
-+ * @change_station: Modify a given station.
-  */
- struct cfg80211_ops {
- 	int	(*add_virtual_intf)(struct wiphy *wiphy, char *name,
-@@ -155,6 +202,13 @@ struct cfg80211_ops {
- 	int	(*set_beacon)(struct wiphy *wiphy, struct net_device *dev,
- 			      struct beacon_parameters *info);
- 	int	(*del_beacon)(struct wiphy *wiphy, struct net_device *dev);
-+
-+	int	(*add_station)(struct wiphy *wiphy, struct net_device *dev,
-+			       u8 *mac, struct station_parameters *params);
-+	int	(*del_station)(struct wiphy *wiphy, struct net_device *dev,
-+			       u8 *mac);
-+	int	(*change_station)(struct wiphy *wiphy, struct net_device *dev,
-+				  u8 *mac, struct station_parameters *params);
- };
- 
- #endif /* __NET_CFG80211_H */
---- everything.orig/net/wireless/nl80211.c	2007-11-08 16:58:36.711524524 +0100
-+++ everything/net/wireless/nl80211.c	2007-11-08 17:15:15.981533909 +0100
-@@ -76,6 +76,12 @@ static struct nla_policy nl80211_policy[
- 				       .len = IEEE80211_MAX_DATA_LEN },
- 	[NL80211_ATTR_BEACON_TAIL] = { .type = NLA_BINARY,
- 				       .len = IEEE80211_MAX_DATA_LEN },
-+	[NL80211_ATTR_STA_AID] = { .type = NLA_U16 },
-+	[NL80211_ATTR_STA_FLAGS] = { .type = NLA_NESTED },
-+	[NL80211_ATTR_STA_LISTEN_INTERVAL] = { .type = NLA_U16 },
-+	[NL80211_ATTR_STA_SUPPORTED_RATES] = { .type = NLA_BINARY,
-+					       .len = NL80211_MAX_SUPP_RATES },
-+	[NL80211_ATTR_STA_VLAN] = { .type = NLA_U32 },
- };
- 
- /* message building helper */
-@@ -715,6 +721,211 @@ static int nl80211_del_beacon(struct sk_
- 	return err;
- }
- 
-+static
-+struct nla_policy sta_flags_policy[NL80211_STA_FLAG_MAX + 1] __read_mostly = {
-+	[NL80211_STA_FLAG_AUTHORIZED] = { .type = NLA_FLAG },
-+	[NL80211_STA_FLAG_SHORT_PREAMBLE] = { .type = NLA_FLAG },
-+	[NL80211_STA_FLAG_WME] = { .type = NLA_FLAG },
-+};
-+
-+static int parse_station_flags(struct nlattr *nla, u32 *staflags)
-+{
-+	struct nlattr *flags[NL80211_STA_FLAG_MAX + 1];
-+	int flag;
-+
-+	*staflags = 0;
-+
-+	if (!nla)
-+		return 0;
-+
-+	if (nla_parse_nested(flags, NL80211_STA_FLAG_MAX,
-+			     nla, sta_flags_policy))
-+		return -EINVAL;
-+
-+	*staflags = STATION_FLAG_CHANGED;
-+
-+	for (flag = 1; flag <= NL80211_STA_FLAG_MAX; flag++)
-+		if (flags[flag])
-+			*staflags |= (1<<flag);
-+
-+	return 0;
-+}
-+
-+static int nl80211_get_station(struct sk_buff *skb, struct genl_info *info)
-+{
-+	return -EOPNOTSUPP;
-+}
-+
-+/*
-+ * Get vlan interface making sure it is on the right wiphy.
-+ */
-+static int get_vlan(struct nlattr *vlanattr,
-+		    struct cfg80211_registered_device *rdev,
-+		    struct net_device **vlan)
-+{
-+	*vlan = NULL;
-+
-+	if (vlanattr) {
-+		*vlan = dev_get_by_index(nla_get_u32(vlanattr));
-+		if (!*vlan)
-+			return -ENODEV;
-+		if (!(*vlan)->ieee80211_ptr)
-+			return -EINVAL;
-+		if ((*vlan)->ieee80211_ptr->wiphy != &rdev->wiphy)
-+			return -EINVAL;
-+	}
-+	return 0;
-+}
-+
-+static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info)
-+{
-+	struct cfg80211_registered_device *drv;
-+	int err;
-+	struct net_device *dev;
-+	struct station_parameters params;
-+	u8 *mac_addr = NULL;
-+
-+	memset(&params, 0, sizeof(params));
-+
-+	params.listen_interval = -1;
-+
-+	if (info->attrs[NL80211_ATTR_STA_AID])
-+		return -EINVAL;
-+
-+	if (!info->attrs[NL80211_ATTR_MAC])
-+		return -EINVAL;
-+
-+	mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
-+
-+	if (info->attrs[NL80211_ATTR_STA_SUPPORTED_RATES]) {
-+		params.supported_rates =
-+			nla_data(info->attrs[NL80211_ATTR_STA_SUPPORTED_RATES]);
-+		params.supported_rates_len =
-+			nla_len(info->attrs[NL80211_ATTR_STA_SUPPORTED_RATES]);
-+	}
-+
-+	if (info->attrs[NL80211_ATTR_STA_LISTEN_INTERVAL])
-+		params.listen_interval =
-+		    nla_get_u16(info->attrs[NL80211_ATTR_STA_LISTEN_INTERVAL]);
-+
-+	if (parse_station_flags(info->attrs[NL80211_ATTR_STA_FLAGS],
-+				&params.station_flags))
-+		return -EINVAL;
-+
-+	err = get_drv_dev_by_info_ifindex(info, &drv, &dev);
-+	if (err)
-+		return err;
-+
-+	err = get_vlan(info->attrs[NL80211_ATTR_STA_VLAN], drv, &params.vlan);
-+	if (err)
-+		goto out;
-+
-+	if (!drv->ops->change_station) {
-+		err = -EOPNOTSUPP;
-+		goto out;
-+	}
-+
-+	rtnl_lock();
-+	err = drv->ops->change_station(&drv->wiphy, dev, mac_addr, &params);
-+	rtnl_unlock();
-+
-+ out:
-+	if (params.vlan)
-+		dev_put(params.vlan);
-+	cfg80211_put_dev(drv);
-+	dev_put(dev);
-+	return err;
-+}
-+
-+static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info)
-+{
-+	struct cfg80211_registered_device *drv;
-+	int err;
-+	struct net_device *dev;
-+	struct station_parameters params;
-+	u8 *mac_addr = NULL;
-+
-+	memset(&params, 0, sizeof(params));
-+
-+	if (!info->attrs[NL80211_ATTR_MAC])
-+		return -EINVAL;
-+
-+	if (!info->attrs[NL80211_ATTR_STA_AID])
-+		return -EINVAL;
-+
-+	if (!info->attrs[NL80211_ATTR_STA_LISTEN_INTERVAL])
-+		return -EINVAL;
-+
-+	if (!info->attrs[NL80211_ATTR_STA_SUPPORTED_RATES])
-+		return -EINVAL;
-+
-+	mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
-+	params.supported_rates =
-+		nla_data(info->attrs[NL80211_ATTR_STA_SUPPORTED_RATES]);
-+	params.supported_rates_len =
-+		nla_len(info->attrs[NL80211_ATTR_STA_SUPPORTED_RATES]);
-+	params.listen_interval =
-+		nla_get_u16(info->attrs[NL80211_ATTR_STA_LISTEN_INTERVAL]);
-+	params.listen_interval = nla_get_u16(info->attrs[NL80211_ATTR_STA_AID]);
-+
-+	if (parse_station_flags(info->attrs[NL80211_ATTR_STA_FLAGS],
-+				&params.station_flags))
-+		return -EINVAL;
-+
-+	err = get_drv_dev_by_info_ifindex(info, &drv, &dev);
-+	if (err)
-+		return err;
-+
-+	err = get_vlan(info->attrs[NL80211_ATTR_STA_VLAN], drv, &params.vlan);
-+	if (err)
-+		goto out;
-+
-+	if (!drv->ops->add_station) {
-+		err = -EOPNOTSUPP;
-+		goto out;
-+	}
-+
-+	rtnl_lock();
-+	err = drv->ops->add_station(&drv->wiphy, dev, mac_addr, &params);
-+	rtnl_unlock();
-+
-+ out:
-+	if (params.vlan)
-+		dev_put(params.vlan);
-+	cfg80211_put_dev(drv);
-+	dev_put(dev);
-+	return err;
-+}
-+
-+static int nl80211_del_station(struct sk_buff *skb, struct genl_info *info)
-+{
-+	struct cfg80211_registered_device *drv;
-+	int err;
-+	struct net_device *dev;
-+	u8 *mac_addr = NULL;
-+
-+	if (info->attrs[NL80211_ATTR_MAC])
-+		mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
-+
-+	err = get_drv_dev_by_info_ifindex(info, &drv, &dev);
-+	if (err)
-+		return err;
-+
-+	if (!drv->ops->del_station) {
-+		err = -EOPNOTSUPP;
-+		goto out;
-+	}
-+
-+	rtnl_lock();
-+	err = drv->ops->del_station(&drv->wiphy, dev, mac_addr);
-+	rtnl_unlock();
-+
-+ out:
-+	cfg80211_put_dev(drv);
-+	dev_put(dev);
-+	return err;
-+}
-+
- static struct genl_ops nl80211_ops[] = {
- 	{
- 		.cmd = NL80211_CMD_GET_WIPHY,
-@@ -796,6 +1007,31 @@ static struct genl_ops nl80211_ops[] = {
- 		.flags = GENL_ADMIN_PERM,
- 		.doit = nl80211_del_beacon,
- 	},
-+	{
-+		.cmd = NL80211_CMD_GET_STATION,
-+		.doit = nl80211_get_station,
-+		/* TODO: implement dumpit */
-+		.policy = nl80211_policy,
-+		.flags = GENL_ADMIN_PERM,
-+	},
-+	{
-+		.cmd = NL80211_CMD_SET_STATION,
-+		.doit = nl80211_set_station,
-+		.policy = nl80211_policy,
-+		.flags = GENL_ADMIN_PERM,
-+	},
-+	{
-+		.cmd = NL80211_CMD_NEW_STATION,
-+		.doit = nl80211_new_station,
-+		.policy = nl80211_policy,
-+		.flags = GENL_ADMIN_PERM,
-+	},
-+	{
-+		.cmd = NL80211_CMD_DEL_STATION,
-+		.doit = nl80211_del_station,
-+		.policy = nl80211_policy,
-+		.flags = GENL_ADMIN_PERM,
-+	},
- };
- 
- /* multicast groups */
diff --git a/package/mac80211/patches/023-mac80211-implement-sta.patch b/package/mac80211/patches/023-mac80211-implement-sta.patch
deleted file mode 100644
index 095067676c..0000000000
--- a/package/mac80211/patches/023-mac80211-implement-sta.patch
+++ /dev/null
@@ -1,224 +0,0 @@
-Subject: mac80211: implement cfg80211's station handling
-
-This implements station handling from userspace via cfg80211
-in mac80211.
-
-Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
-
----
- net/mac80211/cfg.c |  192 +++++++++++++++++++++++++++++++++++++++++++++++++++++
- 1 file changed, 192 insertions(+)
-
---- everything.orig/net/mac80211/cfg.c	2007-11-08 17:11:52.351521702 +0100
-+++ everything/net/mac80211/cfg.c	2007-11-08 17:15:51.801523493 +0100
-@@ -14,6 +14,7 @@
- #include <net/cfg80211.h>
- #include "ieee80211_i.h"
- #include "cfg.h"
-+#include "ieee80211_rate.h"
- 
- static enum ieee80211_if_types
- nl80211_type_to_mac80211_type(enum nl80211_iftype type)
-@@ -428,6 +429,194 @@ static int ieee80211_del_beacon(struct w
- 	return ieee80211_if_config_beacon(dev);
- }
- 
-+/* Layer 2 Update frame (802.2 Type 1 LLC XID Update response) */
-+struct iapp_layer2_update {
-+	u8 da[ETH_ALEN];	/* broadcast */
-+	u8 sa[ETH_ALEN];	/* STA addr */
-+	__be16 len;		/* 6 */
-+	u8 dsap;		/* 0 */
-+	u8 ssap;		/* 0 */
-+	u8 control;
-+	u8 xid_info[3];
-+} __attribute__ ((packed));
-+
-+static void ieee80211_send_layer2_update(struct sta_info *sta)
-+{
-+	struct iapp_layer2_update *msg;
-+	struct sk_buff *skb;
-+
-+	/* Send Level 2 Update Frame to update forwarding tables in layer 2
-+	 * bridge devices */
-+
-+	skb = dev_alloc_skb(sizeof(*msg));
-+	if (!skb)
-+		return;
-+	msg = (struct iapp_layer2_update *)skb_put(skb, sizeof(*msg));
-+
-+	/* 802.2 Type 1 Logical Link Control (LLC) Exchange Identifier (XID)
-+	 * Update response frame; IEEE Std 802.2-1998, 5.4.1.2.1 */
-+
-+	memset(msg->da, 0xff, ETH_ALEN);
-+	memcpy(msg->sa, sta->addr, ETH_ALEN);
-+	msg->len = htons(6);
-+	msg->dsap = 0;
-+	msg->ssap = 0x01;	/* NULL LSAP, CR Bit: Response */
-+	msg->control = 0xaf;	/* XID response lsb.1111F101.
-+				 * F=0 (no poll command; unsolicited frame) */
-+	msg->xid_info[0] = 0x81;	/* XID format identifier */
-+	msg->xid_info[1] = 1;	/* LLC types/classes: Type 1 LLC */
-+	msg->xid_info[2] = 0;	/* XID sender's receive window size (RW) */
-+
-+	skb->dev = sta->dev;
-+	skb->protocol = eth_type_trans(skb, sta->dev);
-+	memset(skb->cb, 0, sizeof(skb->cb));
-+	netif_rx(skb);
-+}
-+
-+static void sta_apply_parameters(struct ieee80211_local *local,
-+				 struct sta_info *sta,
-+				 struct station_parameters *params)
-+{
-+	u32 rates;
-+	int i, j;
-+	struct ieee80211_hw_mode *mode;
-+
-+	if (params->station_flags & STATION_FLAG_CHANGED) {
-+		sta->flags &= ~WLAN_STA_AUTHORIZED;
-+		if (params->station_flags & STATION_FLAG_AUTHORIZED)
-+			sta->flags |= WLAN_STA_AUTHORIZED;
-+
-+		sta->flags &= ~WLAN_STA_SHORT_PREAMBLE;
-+		if (params->station_flags & STATION_FLAG_SHORT_PREAMBLE)
-+			sta->flags |= WLAN_STA_SHORT_PREAMBLE;
-+
-+		sta->flags &= ~WLAN_STA_WME;
-+		if (params->station_flags & STATION_FLAG_WME)
-+			sta->flags |= WLAN_STA_WME;
-+	}
-+
-+	if (params->aid) {
-+		sta->aid = params->aid;
-+		if (sta->aid > IEEE80211_MAX_AID)
-+			sta->aid = 0; /* XXX: should this be an error? */
-+	}
-+
-+	if (params->listen_interval >= 0)
-+		sta->listen_interval = params->listen_interval;
-+
-+	if (params->supported_rates) {
-+		rates = 0;
-+		mode = local->oper_hw_mode;
-+		for (i = 0; i < params->supported_rates_len; i++) {
-+			int rate = (params->supported_rates[i] & 0x7f) * 5;
-+			for (j = 0; j < mode->num_rates; j++) {
-+				if (mode->rates[j].rate == rate)
-+					rates |= BIT(j);
-+			}
-+		}
-+		sta->supp_rates = rates;
-+	}
-+}
-+
-+static int ieee80211_add_station(struct wiphy *wiphy, struct net_device *dev,
-+				 u8 *mac, struct station_parameters *params)
-+{
-+	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
-+	struct sta_info *sta;
-+	struct ieee80211_sub_if_data *sdata;
-+
-+	/* Prevent a race with changing the rate control algorithm */
-+	if (!netif_running(dev))
-+		return -ENETDOWN;
-+
-+	/* XXX: get sta belonging to dev */
-+	sta = sta_info_get(local, mac);
-+	if (sta) {
-+		sta_info_put(sta);
-+		return -EEXIST;
-+	}
-+
-+	if (params->vlan) {
-+		sdata = IEEE80211_DEV_TO_SUB_IF(params->vlan);
-+
-+		if (sdata->type != IEEE80211_IF_TYPE_VLAN ||
-+		    sdata->type != IEEE80211_IF_TYPE_AP)
-+			return -EINVAL;
-+	} else
-+		sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-+
-+	sta = sta_info_add(local, dev, mac, GFP_KERNEL);
-+	if (!sta)
-+		return -ENOMEM;
-+
-+	sta->dev = sdata->dev;
-+	if (sdata->type == IEEE80211_IF_TYPE_VLAN ||
-+	    sdata->type == IEEE80211_IF_TYPE_AP)
-+		ieee80211_send_layer2_update(sta);
-+
-+	sta->flags = WLAN_STA_AUTH | WLAN_STA_ASSOC;
-+
-+	sta_apply_parameters(local, sta, params);
-+
-+	rate_control_rate_init(sta, local);
-+
-+	sta_info_put(sta);
-+
-+	return 0;
-+}
-+
-+static int ieee80211_del_station(struct wiphy *wiphy, struct net_device *dev,
-+				 u8 *mac)
-+{
-+	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
-+	struct sta_info *sta;
-+
-+	if (mac) {
-+		/* XXX: get sta belonging to dev */
-+		sta = sta_info_get(local, mac);
-+		if (!sta)
-+			return -ENOENT;
-+
-+		sta_info_free(sta);
-+		sta_info_put(sta);
-+	} else
-+		sta_info_flush(local, dev);
-+
-+	return 0;
-+}
-+
-+static int ieee80211_change_station(struct wiphy *wiphy,
-+				    struct net_device *dev,
-+				    u8 *mac,
-+				    struct station_parameters *params)
-+{
-+	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
-+	struct sta_info *sta;
-+	struct ieee80211_sub_if_data *vlansdata;
-+
-+	/* XXX: get sta belonging to dev */
-+	sta = sta_info_get(local, mac);
-+	if (!sta)
-+		return -ENOENT;
-+
-+	if (params->vlan && params->vlan != sta->dev) {
-+		vlansdata = IEEE80211_DEV_TO_SUB_IF(params->vlan);
-+
-+		if (vlansdata->type != IEEE80211_IF_TYPE_VLAN ||
-+		    vlansdata->type != IEEE80211_IF_TYPE_AP)
-+			return -EINVAL;
-+
-+		sta->dev = params->vlan;
-+		ieee80211_send_layer2_update(sta);
-+	}
-+
-+	sta_apply_parameters(local, sta, params);
-+
-+	sta_info_put(sta);
-+
-+	return 0;
-+}
-+
- struct cfg80211_ops mac80211_config_ops = {
- 	.add_virtual_intf = ieee80211_add_iface,
- 	.del_virtual_intf = ieee80211_del_iface,
-@@ -439,4 +628,7 @@ struct cfg80211_ops mac80211_config_ops 
- 	.add_beacon = ieee80211_add_beacon,
- 	.set_beacon = ieee80211_set_beacon,
- 	.del_beacon = ieee80211_del_beacon,
-+	.add_station = ieee80211_add_station,
-+	.del_station = ieee80211_del_station,
-+	.change_station = ieee80211_change_station,
- };
diff --git a/package/mac80211/patches/024-nl80211-get-sta.patch b/package/mac80211/patches/024-nl80211-get-sta.patch
deleted file mode 100644
index 198ad1876b..0000000000
--- a/package/mac80211/patches/024-nl80211-get-sta.patch
+++ /dev/null
@@ -1,208 +0,0 @@
-Subject: cfg80211/nl80211: implement station attribute retrieval
-
-After a station is added to the kernel's structures, userspace
-has to be able to retrieve statistics about that station, especially
-whether the station was idle and how much bytes were transferred
-to and from it. This adds the necessary code to nl80211.
-
-Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
-
----
- include/linux/nl80211.h |   28 ++++++++++++++++
- include/net/cfg80211.h  |   35 ++++++++++++++++++++
- net/wireless/nl80211.c  |   82 +++++++++++++++++++++++++++++++++++++++++++++++-
- 3 files changed, 144 insertions(+), 1 deletion(-)
-
---- everything.orig/include/linux/nl80211.h	2007-11-08 17:15:15.961529840 +0100
-+++ everything/include/linux/nl80211.h	2007-11-08 17:17:00.891547364 +0100
-@@ -157,6 +157,9 @@ enum nl80211_commands {
-  *	restriction (at most %NL80211_MAX_SUPP_RATES).
-  * @NL80211_ATTR_STA_VLAN: interface index of VLAN interface to move station
-  *	to, or the AP interface the station was originally added to to.
-+ * @NL80211_ATTR_STA_STATS: statistics for a station, part of station info
-+ *	given for %NL80211_CMD_GET_STATION, nested attribute containing
-+ *	info as possible, see &enum nl80211_sta_stats.
-  *
-  * @NL80211_ATTR_MAX: highest attribute number currently defined
-  * @__NL80211_ATTR_AFTER_LAST: internal use
-@@ -190,6 +193,7 @@ enum nl80211_attrs {
- 	NL80211_ATTR_STA_LISTEN_INTERVAL,
- 	NL80211_ATTR_STA_SUPPORTED_RATES,
- 	NL80211_ATTR_STA_VLAN,
-+	NL80211_ATTR_STA_STATS,
- 
- 	/* add attributes here, update the policy in nl80211.c */
- 
-@@ -252,4 +256,28 @@ enum nl80211_sta_flags {
- 	NL80211_STA_FLAG_MAX = __NL80211_STA_FLAG_AFTER_LAST - 1
- };
- 
-+/**
-+ * enum nl80211_sta_stats - station statistics
-+ *
-+ * These attribute types are used with %NL80211_ATTR_STA_STATS
-+ * when getting information about a station.
-+ *
-+ * @__NL80211_STA_STAT_INVALID: attribute number 0 is reserved
-+ * @NL80211_STA_STAT_INACTIVE_TIME: time since last activity (u32, msecs)
-+ * @NL80211_STA_STAT_RX_BYTES: total received bytes (u32, from this station)
-+ * @NL80211_STA_STAT_TX_BYTES: total transmitted bytes (u32, to this station)
-+ * @__NL80211_STA_STAT_AFTER_LAST: internal
-+ * @NL80211_STA_STAT_MAX: highest possible station stats attribute
-+ */
-+enum nl80211_sta_stats {
-+	__NL80211_STA_STAT_INVALID,
-+	NL80211_STA_STAT_INACTIVE_TIME,
-+	NL80211_STA_STAT_RX_BYTES,
-+	NL80211_STA_STAT_TX_BYTES,
-+
-+	/* keep last */
-+	__NL80211_STA_STAT_AFTER_LAST,
-+	NL80211_STA_STAT_MAX = __NL80211_STA_STAT_AFTER_LAST - 1
-+};
-+
- #endif /* __LINUX_NL80211_H */
---- everything.orig/include/net/cfg80211.h	2007-11-08 17:15:15.971532444 +0100
-+++ everything/include/net/cfg80211.h	2007-11-08 17:17:00.891547364 +0100
-@@ -130,6 +130,39 @@ struct station_parameters {
- 	u8 supported_rates_len;
- };
- 
-+/**
-+ * enum station_stats_flags - station statistics flags
-+ *
-+ * Used by the driver to indicate which info in &struct station_stats
-+ * it has filled in during get_station().
-+ *
-+ * @STATION_STAT_INACTIVE_TIME: @inactive_time filled
-+ * @STATION_STAT_RX_BYTES: @rx_bytes filled
-+ * @STATION_STAT_TX_BYTES: @tx_bytes filled
-+ */
-+enum station_stats_flags {
-+	STATION_STAT_INACTIVE_TIME	= 1<<0,
-+	STATION_STAT_RX_BYTES		= 1<<1,
-+	STATION_STAT_TX_BYTES		= 1<<2,
-+};
-+
-+/**
-+ * struct station_stats - station statistics
-+ *
-+ * Station information filled by driver for get_station().
-+ *
-+ * @filled: bitflag of flags from &enum station_stats_flags
-+ * @inactive_time: time since last station activity (tx/rx) in milliseconds
-+ * @rx_bytes: bytes received from this station
-+ * @tx_bytes: bytes transmitted to this station
-+ */
-+struct station_stats {
-+	u32 filled;
-+	u32 inactive_time;
-+	u32 rx_bytes;
-+	u32 tx_bytes;
-+};
-+
- /* from net/wireless.h */
- struct wiphy;
- 
-@@ -209,6 +242,8 @@ struct cfg80211_ops {
- 			       u8 *mac);
- 	int	(*change_station)(struct wiphy *wiphy, struct net_device *dev,
- 				  u8 *mac, struct station_parameters *params);
-+	int	(*get_station)(struct wiphy *wiphy, struct net_device *dev,
-+			       u8 *mac, struct station_stats *stats);
- };
- 
- #endif /* __NET_CFG80211_H */
---- everything.orig/net/wireless/nl80211.c	2007-11-08 17:15:15.981533909 +0100
-+++ everything/net/wireless/nl80211.c	2007-11-08 17:17:00.901534235 +0100
-@@ -751,9 +751,89 @@ static int parse_station_flags(struct nl
- 	return 0;
- }
- 
-+static int nl80211_send_station(struct sk_buff *msg, u32 pid, u32 seq,
-+				int flags, struct net_device *dev,
-+				u8 *mac_addr, struct station_stats *stats)
-+{
-+	void *hdr;
-+	struct nlattr *statsattr;
-+
-+	hdr = nl80211hdr_put(msg, pid, seq, flags, NL80211_CMD_NEW_STATION);
-+	if (!hdr)
-+		return -1;
-+
-+	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, dev->ifindex);
-+	NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, mac_addr);
-+
-+	statsattr = nla_nest_start(msg, NL80211_ATTR_STA_STATS);
-+	if (!statsattr)
-+		goto nla_put_failure;
-+	if (stats->filled & STATION_STAT_INACTIVE_TIME)
-+		NLA_PUT_U32(msg, NL80211_STA_STAT_INACTIVE_TIME,
-+			    stats->inactive_time);
-+	if (stats->filled & STATION_STAT_RX_BYTES)
-+		NLA_PUT_U32(msg, NL80211_STA_STAT_RX_BYTES,
-+			    stats->rx_bytes);
-+	if (stats->filled & STATION_STAT_TX_BYTES)
-+		NLA_PUT_U32(msg, NL80211_STA_STAT_TX_BYTES,
-+			    stats->tx_bytes);
-+
-+	nla_nest_end(msg, statsattr);
-+
-+	return genlmsg_end(msg, hdr);
-+
-+ nla_put_failure:
-+	return genlmsg_cancel(msg, hdr);
-+}
-+
-+
- static int nl80211_get_station(struct sk_buff *skb, struct genl_info *info)
- {
--	return -EOPNOTSUPP;
-+	struct cfg80211_registered_device *drv;
-+	int err;
-+	struct net_device *dev;
-+	struct station_stats stats;
-+	struct sk_buff *msg;
-+	u8 *mac_addr = NULL;
-+
-+	memset(&stats, 0, sizeof(stats));
-+
-+	if (!info->attrs[NL80211_ATTR_MAC])
-+		return -EINVAL;
-+
-+	mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
-+
-+	err = get_drv_dev_by_info_ifindex(info, &drv, &dev);
-+	if (err)
-+		return err;
-+
-+	if (!drv->ops->get_station) {
-+		err = -EOPNOTSUPP;
-+		goto out;
-+	}
-+
-+	rtnl_lock();
-+	err = drv->ops->get_station(&drv->wiphy, dev, mac_addr, &stats);
-+	rtnl_unlock();
-+
-+	msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
-+	if (!msg)
-+		goto out;
-+
-+	if (nl80211_send_station(msg, info->snd_pid, info->snd_seq, 0,
-+				 dev, mac_addr, &stats) < 0)
-+		goto out_free;
-+
-+	err = genlmsg_unicast(msg, info->snd_pid);
-+	goto out;
-+
-+ out_free:
-+	nlmsg_free(msg);
-+
-+ out:
-+	cfg80211_put_dev(drv);
-+	dev_put(dev);
-+	return err;
- }
- 
- /*
diff --git a/package/mac80211/patches/025-mac80211-get-sta.patch b/package/mac80211/patches/025-mac80211-get-sta.patch
deleted file mode 100644
index 868ca86fa3..0000000000
--- a/package/mac80211/patches/025-mac80211-get-sta.patch
+++ /dev/null
@@ -1,51 +0,0 @@
-Subject: mac80211: implement station stats retrieval
-
-This implements the required cfg80211 callback in mac80211
-to allow userspace to get station statistics.
-
-Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
-
----
- net/mac80211/cfg.c |   26 ++++++++++++++++++++++++++
- 1 file changed, 26 insertions(+)
-
---- everything.orig/net/mac80211/cfg.c	2007-11-08 17:15:51.801523493 +0100
-+++ everything/net/mac80211/cfg.c	2007-11-08 17:17:01.921529351 +0100
-@@ -617,6 +617,31 @@ static int ieee80211_change_station(stru
- 	return 0;
- }
- 
-+static int ieee80211_get_station(struct wiphy *wiphy, struct net_device *dev,
-+				 u8 *mac, struct station_stats *stats)
-+{
-+	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
-+	struct sta_info *sta;
-+
-+	sta = sta_info_get(local, mac);
-+	if (!sta)
-+		return -ENOENT;
-+
-+	/* XXX: verify sta->dev == dev */
-+
-+	stats->filled = STATION_STAT_INACTIVE_TIME |
-+			STATION_STAT_RX_BYTES |
-+			STATION_STAT_TX_BYTES;
-+
-+	stats->inactive_time = jiffies_to_msecs(jiffies - sta->last_rx);
-+	stats->rx_bytes = sta->rx_bytes;
-+	stats->tx_bytes = sta->tx_bytes;
-+
-+	sta_info_put(sta);
-+
-+	return 0;
-+}
-+
- struct cfg80211_ops mac80211_config_ops = {
- 	.add_virtual_intf = ieee80211_add_iface,
- 	.del_virtual_intf = ieee80211_del_iface,
-@@ -631,4 +656,5 @@ struct cfg80211_ops mac80211_config_ops 
- 	.add_station = ieee80211_add_station,
- 	.del_station = ieee80211_del_station,
- 	.change_station = ieee80211_change_station,
-+	.get_station = ieee80211_get_station,
- };
diff --git a/package/mac80211/src/include/linux/ieee80211.h b/package/mac80211/src/include/linux/ieee80211.h
index 30621c2715..f577c8f1c6 100644
--- a/package/mac80211/src/include/linux/ieee80211.h
+++ b/package/mac80211/src/include/linux/ieee80211.h
@@ -54,6 +54,8 @@
 #define IEEE80211_STYPE_ACTION		0x00D0
 
 /* control */
+#define IEEE80211_STYPE_BACK_REQ	0x0080
+#define IEEE80211_STYPE_BACK		0x0090
 #define IEEE80211_STYPE_PSPOLL		0x00A0
 #define IEEE80211_STYPE_RTS		0x00B0
 #define IEEE80211_STYPE_CTS		0x00C0
@@ -81,18 +83,18 @@
 
 
 /* miscellaneous IEEE 802.11 constants */
-#define IEEE80211_MAX_FRAG_THRESHOLD	2346
-#define IEEE80211_MAX_RTS_THRESHOLD	2347
+#define IEEE80211_MAX_FRAG_THRESHOLD	2352
+#define IEEE80211_MAX_RTS_THRESHOLD	2353
 #define IEEE80211_MAX_AID		2007
 #define IEEE80211_MAX_TIM_LEN		251
-#define IEEE80211_MAX_DATA_LEN		2304
 /* Maximum size for the MA-UNITDATA primitive, 802.11 standard section
    6.2.1.1.2.
 
-   The figure in section 7.1.2 suggests a body size of up to 2312
-   bytes is allowed, which is a bit confusing, I suspect this
-   represents the 2304 bytes of real data, plus a possible 8 bytes of
-   WEP IV and ICV. (this interpretation suggested by Ramiro Barreiro) */
+   802.11e clarifies the figure in section 7.1.2. The frame body is
+   up to 2304 octets long (maximum MSDU size) plus any crypt overhead. */
+#define IEEE80211_MAX_DATA_LEN		2304
+/* 30 byte 4 addr hdr, 2 byte QoS, 2304 byte MSDU, 12 byte crypt, 4 byte FCS */
+#define IEEE80211_MAX_FRAME_LEN		2352
 
 #define IEEE80211_MAX_SSID_LEN		32
 
@@ -185,6 +187,25 @@ struct ieee80211_mgmt {
 					u8 new_chan;
 					u8 switch_count;
 				} __attribute__((packed)) chan_switch;
+				struct{
+					u8 action_code;
+					u8 dialog_token;
+					__le16 capab;
+					__le16 timeout;
+					__le16 start_seq_num;
+				} __attribute__((packed)) addba_req;
+				struct{
+					u8 action_code;
+					u8 dialog_token;
+					__le16 status;
+					__le16 capab;
+					__le16 timeout;
+				} __attribute__((packed)) addba_resp;
+				struct{
+					u8 action_code;
+					__le16 params;
+					__le16 reason_code;
+				} __attribute__((packed)) delba;
 			} u;
 		} __attribute__ ((packed)) action;
 	} u;
@@ -205,6 +226,72 @@ struct ieee80211_cts {
 	u8 ra[6];
 } __attribute__ ((packed));
 
+/**
+ * struct ieee80211_bar - HT Block Ack Request
+ *
+ * This structure refers to "HT BlockAckReq" as
+ * described in 802.11n draft section 7.2.1.7.1
+ */
+struct ieee80211_bar {
+	__le16 frame_control;
+	__le16 duration;
+	__u8 ra[6];
+	__u8 ta[6];
+	__le16 control;
+	__le16 start_seq_num;
+} __attribute__((packed));
+
+/**
+ * struct ieee80211_ht_cap - HT capabilities
+ *
+ * This structure refers to "HT capabilities element" as
+ * described in 802.11n draft section 7.3.2.52
+ */
+struct ieee80211_ht_cap {
+	__le16 cap_info;
+	u8 ampdu_params_info;
+	u8 supp_mcs_set[16];
+	__le16 extended_ht_cap_info;
+	__le32 tx_BF_cap_info;
+	u8 antenna_selection_info;
+} __attribute__ ((packed));
+
+/**
+ * struct ieee80211_ht_cap - HT additional information
+ *
+ * This structure refers to "HT information element" as
+ * described in 802.11n draft section 7.3.2.53
+ */
+struct ieee80211_ht_addt_info {
+	u8 control_chan;
+	u8 ht_param;
+	__le16 operation_mode;
+	__le16 stbc_param;
+	u8 basic_set[16];
+} __attribute__ ((packed));
+
+/* 802.11n HT capabilities masks */
+#define IEEE80211_HT_CAP_SUP_WIDTH		0x0002
+#define IEEE80211_HT_CAP_MIMO_PS		0x000C
+#define IEEE80211_HT_CAP_GRN_FLD		0x0010
+#define IEEE80211_HT_CAP_SGI_20			0x0020
+#define IEEE80211_HT_CAP_SGI_40			0x0040
+#define IEEE80211_HT_CAP_DELAY_BA		0x0400
+#define IEEE80211_HT_CAP_MAX_AMSDU		0x0800
+#define IEEE80211_HT_CAP_AMPDU_FACTOR		0x03
+#define IEEE80211_HT_CAP_AMPDU_DENSITY		0x1C
+/* 802.11n HT IE masks */
+#define IEEE80211_HT_IE_CHA_SEC_OFFSET		0x03
+#define IEEE80211_HT_IE_CHA_WIDTH		0x04
+#define IEEE80211_HT_IE_HT_PROTECTION		0x0003
+#define IEEE80211_HT_IE_NON_GF_STA_PRSNT	0x0004
+#define IEEE80211_HT_IE_NON_HT_STA_PRSNT	0x0010
+
+/* MIMO Power Save Modes */
+#define WLAN_HT_CAP_MIMO_PS_STATIC         0
+#define WLAN_HT_CAP_MIMO_PS_DYNAMIC        1
+#define WLAN_HT_CAP_MIMO_PS_INVALID        2
+#define WLAN_HT_CAP_MIMO_PS_DISABLED       3
 
 /* Authentication algorithms */
 #define WLAN_AUTH_OPEN 0
@@ -271,6 +358,18 @@ enum ieee80211_statuscode {
 	WLAN_STATUS_UNSUPP_RSN_VERSION = 44,
 	WLAN_STATUS_INVALID_RSN_IE_CAP = 45,
 	WLAN_STATUS_CIPHER_SUITE_REJECTED = 46,
+	/* 802.11e */
+	WLAN_STATUS_UNSPECIFIED_QOS = 32,
+	WLAN_STATUS_ASSOC_DENIED_NOBANDWIDTH = 33,
+	WLAN_STATUS_ASSOC_DENIED_LOWACK = 34,
+	WLAN_STATUS_ASSOC_DENIED_UNSUPP_QOS = 35,
+	WLAN_STATUS_REQUEST_DECLINED = 37,
+	WLAN_STATUS_INVALID_QOS_PARAM = 38,
+	WLAN_STATUS_CHANGE_TSPEC = 39,
+	WLAN_STATUS_WAIT_TS_DELAY = 47,
+	WLAN_STATUS_NO_DIRECT_LINK = 48,
+	WLAN_STATUS_STA_NOT_PRESENT = 49,
+	WLAN_STATUS_STA_NOT_QSTA = 50,
 };
 
 
@@ -301,6 +400,16 @@ enum ieee80211_reasoncode {
 	WLAN_REASON_INVALID_RSN_IE_CAP = 22,
 	WLAN_REASON_IEEE8021X_FAILED = 23,
 	WLAN_REASON_CIPHER_SUITE_REJECTED = 24,
+	/* 802.11e */
+	WLAN_REASON_DISASSOC_UNSPECIFIED_QOS = 32,
+	WLAN_REASON_DISASSOC_QAP_NO_BANDWIDTH = 33,
+	WLAN_REASON_DISASSOC_LOW_ACK = 34,
+	WLAN_REASON_DISASSOC_QAP_EXCEED_TXOP = 35,
+	WLAN_REASON_QSTA_LEAVE_QBSS = 36,
+	WLAN_REASON_QSTA_NOT_USE = 37,
+	WLAN_REASON_QSTA_REQUIRE_SETUP = 38,
+	WLAN_REASON_QSTA_TIMEOUT = 39,
+	WLAN_REASON_QSTA_CIPHER_NOT_SUPP = 45,
 };
 
 
@@ -319,6 +428,15 @@ enum ieee80211_eid {
 	WLAN_EID_HP_PARAMS = 8,
 	WLAN_EID_HP_TABLE = 9,
 	WLAN_EID_REQUEST = 10,
+	/* 802.11e */
+	WLAN_EID_QBSS_LOAD = 11,
+	WLAN_EID_EDCA_PARAM_SET = 12,
+	WLAN_EID_TSPEC = 13,
+	WLAN_EID_TCLAS = 14,
+	WLAN_EID_SCHEDULE = 15,
+	WLAN_EID_TS_DELAY = 43,
+	WLAN_EID_TCLAS_PROCESSING = 44,
+	WLAN_EID_QOS_CAPA = 46,
 	/* 802.11h */
 	WLAN_EID_PWR_CONSTRAINT = 32,
 	WLAN_EID_PWR_CAPABILITY = 33,
@@ -333,6 +451,9 @@ enum ieee80211_eid {
 	/* 802.11g */
 	WLAN_EID_ERP_INFO = 42,
 	WLAN_EID_EXT_SUPP_RATES = 50,
+	/* 802.11n */
+	WLAN_EID_HT_CAPABILITY = 45,
+	WLAN_EID_HT_EXTRA_INFO = 61,
 	/* 802.11i */
 	WLAN_EID_RSN = 48,
 	WLAN_EID_WPA = 221,
@@ -341,6 +462,32 @@ enum ieee80211_eid {
 	WLAN_EID_QOS_PARAMETER = 222
 };
 
+/* Action category code */
+enum ieee80211_category {
+	WLAN_CATEGORY_SPECTRUM_MGMT = 0,
+	WLAN_CATEGORY_QOS = 1,
+	WLAN_CATEGORY_DLS = 2,
+	WLAN_CATEGORY_BACK = 3,
+	WLAN_CATEGORY_WMM = 17,
+};
+
+/* BACK action code */
+enum ieee80211_back_actioncode {
+	WLAN_ACTION_ADDBA_REQ = 0,
+	WLAN_ACTION_ADDBA_RESP = 1,
+	WLAN_ACTION_DELBA = 2,
+};
+
+/* BACK (block-ack) parties */
+enum ieee80211_back_parties {
+	WLAN_BACK_RECIPIENT = 0,
+	WLAN_BACK_INITIATOR = 1,
+	WLAN_BACK_TIMER = 2,
+};
+
+/* A-MSDU 802.11n */
+#define IEEE80211_QOS_CONTROL_A_MSDU_PRESENT 0x0080
+
 /* cipher suite selectors */
 #define WLAN_CIPHER_SUITE_USE_GROUP	0x000FAC00
 #define WLAN_CIPHER_SUITE_WEP40		0x000FAC01
diff --git a/package/mac80211/src/include/linux/nl80211.h b/package/mac80211/src/include/linux/nl80211.h
index a5dd030d50..a9f0b93324 100644
--- a/package/mac80211/src/include/linux/nl80211.h
+++ b/package/mac80211/src/include/linux/nl80211.h
@@ -6,6 +6,18 @@
  * Copyright 2006, 2007 Johannes Berg <johannes@sipsolutions.net>
  */
 
+/**
+ * DOC: Station handling
+ *
+ * Stations are added per interface, but a special case exists with VLAN
+ * interfaces. When a station is bound to an AP interface, it may be moved
+ * into a VLAN identified by a VLAN interface index (%NL80211_ATTR_STA_VLAN).
+ * The station is still assumed to belong to the AP interface it was added
+ * to.
+ *
+ * TODO: need more info?
+ */
+
 /**
  * enum nl80211_commands - supported nl80211 commands
  *
@@ -25,7 +37,7 @@
  *	either a dump request on a %NL80211_ATTR_WIPHY or a specific get
  *	on an %NL80211_ATTR_IFINDEX is supported.
  * @NL80211_CMD_SET_INTERFACE: Set type of a virtual interface, requires
- 	%NL80211_ATTR_IFINDEX and %NL80211_ATTR_IFTYPE.
+ *	%NL80211_ATTR_IFINDEX and %NL80211_ATTR_IFTYPE.
  * @NL80211_CMD_NEW_INTERFACE: Newly created virtual interface or response
  *	to %NL80211_CMD_GET_INTERFACE. Has %NL80211_ATTR_IFINDEX,
  *	%NL80211_ATTR_WIPHY and %NL80211_ATTR_IFTYPE attributes. Can also
@@ -37,6 +49,35 @@
  *	userspace to request deletion of a virtual interface, then requires
  *	attribute %NL80211_ATTR_IFINDEX.
  *
+ * @NL80211_CMD_GET_KEY: Get sequence counter information for a key specified
+ *	by %NL80211_ATTR_KEY_IDX and/or %NL80211_ATTR_MAC.
+ * @NL80211_CMD_SET_KEY: Set key attributes %NL80211_ATTR_KEY_DEFAULT or
+ *	%NL80211_ATTR_KEY_THRESHOLD.
+ * @NL80211_CMD_NEW_KEY: add a key with given %NL80211_ATTR_KEY_DATA,
+ *	%NL80211_ATTR_KEY_IDX, %NL80211_ATTR_MAC and %NL80211_ATTR_KEY_CIPHER
+ *	attributes.
+ * @NL80211_CMD_DEL_KEY: delete a key identified by %NL80211_ATTR_KEY_IDX
+ *	or %NL80211_ATTR_MAC.
+ *
+ * @NL80211_CMD_GET_BEACON: retrieve beacon information (returned in a
+ *	%NL80222_CMD_NEW_BEACON message)
+ * @NL80211_CMD_SET_BEACON: set the beacon on an access point interface
+ *	using the %NL80211_ATTR_BEACON_INTERVAL, %NL80211_ATTR_DTIM_PERIOD,
+ *	%NL80211_BEACON_HEAD and %NL80211_BEACON_TAIL attributes.
+ * @NL80211_CMD_NEW_BEACON: add a new beacon to an access point interface,
+ *	parameters are like for %NL80211_CMD_SET_BEACON.
+ * @NL80211_CMD_DEL_BEACON: remove the beacon, stop sending it
+ *
+ * @NL80211_CMD_GET_STATION: Get station attributes for station identified by
+ *	%NL80211_ATTR_MAC on the interface identified by %NL80211_ATTR_IFINDEX.
+ * @NL80211_CMD_SET_STATION: Set station attributes for station identified by
+ *	%NL80211_ATTR_MAC on the interface identified by %NL80211_ATTR_IFINDEX.
+ * @NL80211_CMD_NEW_STATION: Add a station with given attributes to the
+ *	the interface identified by %NL80211_ATTR_IFINDEX.
+ * @NL80211_CMD_DEL_STATION: Remove a station identified by %NL80211_ATTR_MAC
+ *	or, if no MAC address given, all stations, on the interface identified
+ *	by %NL80211_ATTR_IFINDEX.
+ *
  * @NL80211_CMD_MAX: highest used command number
  * @__NL80211_CMD_AFTER_LAST: internal use
  */
@@ -54,6 +95,21 @@ enum nl80211_commands {
 	NL80211_CMD_NEW_INTERFACE,
 	NL80211_CMD_DEL_INTERFACE,
 
+	NL80211_CMD_GET_KEY,
+	NL80211_CMD_SET_KEY,
+	NL80211_CMD_NEW_KEY,
+	NL80211_CMD_DEL_KEY,
+
+	NL80211_CMD_GET_BEACON,
+	NL80211_CMD_SET_BEACON,
+	NL80211_CMD_NEW_BEACON,
+	NL80211_CMD_DEL_BEACON,
+
+	NL80211_CMD_GET_STATION,
+	NL80211_CMD_SET_STATION,
+	NL80211_CMD_NEW_STATION,
+	NL80211_CMD_DEL_STATION,
+
 	/* add commands here */
 
 	/* used to define NL80211_CMD_MAX below */
@@ -75,6 +131,42 @@ enum nl80211_commands {
  * @NL80211_ATTR_IFNAME: network interface name
  * @NL80211_ATTR_IFTYPE: type of virtual interface, see &enum nl80211_iftype
  *
+ * @NL80211_ATTR_MAC: MAC address (various uses)
+ *
+ * @NL80211_ATTR_KEY_DATA: (temporal) key data; for TKIP this consists of
+ *	16 bytes encryption key followed by 8 bytes each for TX and RX MIC
+ *	keys
+ * @NL80211_ATTR_KEY_IDX: key ID (u8, 0-3)
+ * @NL80211_ATTR_KEY_CIPHER: key cipher suite (u32, as defined by IEEE 802.11
+ *	section 7.3.2.25.1, e.g. 0x000FAC04)
+ * @NL80211_ATTR_KEY_SEQ: transmit key sequence number (IV/PN) for TKIP and
+ *	CCMP keys, each six bytes in little endian
+ *
+ * @NL80211_ATTR_BEACON_INTERVAL: beacon interval in TU
+ * @NL80211_ATTR_DTIM_PERIOD: DTIM period for beaconing
+ * @NL80211_ATTR_BEACON_HEAD: portion of the beacon before the TIM IE
+ * @NL80211_ATTR_BEACON_TAIL: portion of the beacon after the TIM IE
+ *
+ * @NL80211_ATTR_STA_AID: Association ID for the station (u16)
+ * @NL80211_ATTR_STA_FLAGS: flags, nested element with NLA_FLAG attributes of
+ *	&enum nl80211_sta_flags.
+ * @NL80211_ATTR_STA_LISTEN_INTERVAL: listen interval as defined by
+ *	IEEE 802.11 7.3.1.6 (u16).
+ * @NL80211_ATTR_STA_SUPPORTED_RATES: supported rates, array of supported
+ *	rates as defined by IEEE 802.11 7.3.2.2 but without the length
+ *	restriction (at most %NL80211_MAX_SUPP_RATES).
+ * @NL80211_ATTR_STA_VLAN: interface index of VLAN interface to move station
+ *	to, or the AP interface the station was originally added to to.
+ * @NL80211_ATTR_STA_STATS: statistics for a station, part of station info
+ *	given for %NL80211_CMD_GET_STATION, nested attribute containing
+ *	info as possible, see &enum nl80211_sta_stats.
+ *
+ * @NL80211_ATTR_WIPHY_BANDS: Information about an operating bands,
+ *	consisting of a nested array.
+ *
+ * @NL80211_ATTR_MNTR_FLAGS: flags, nested element with NLA_FLAG attributes of
+ *      &enum nl80211_mntr_flags.
+ *
  * @NL80211_ATTR_MAX: highest attribute number currently defined
  * @__NL80211_ATTR_AFTER_LAST: internal use
  */
@@ -89,12 +181,38 @@ enum nl80211_attrs {
 	NL80211_ATTR_IFNAME,
 	NL80211_ATTR_IFTYPE,
 
+	NL80211_ATTR_MAC,
+
+	NL80211_ATTR_KEY_DATA,
+	NL80211_ATTR_KEY_IDX,
+	NL80211_ATTR_KEY_CIPHER,
+	NL80211_ATTR_KEY_SEQ,
+	NL80211_ATTR_KEY_DEFAULT,
+
+	NL80211_ATTR_BEACON_INTERVAL,
+	NL80211_ATTR_DTIM_PERIOD,
+	NL80211_ATTR_BEACON_HEAD,
+	NL80211_ATTR_BEACON_TAIL,
+
+	NL80211_ATTR_STA_AID,
+	NL80211_ATTR_STA_FLAGS,
+	NL80211_ATTR_STA_LISTEN_INTERVAL,
+	NL80211_ATTR_STA_SUPPORTED_RATES,
+	NL80211_ATTR_STA_VLAN,
+	NL80211_ATTR_STA_STATS,
+
+	NL80211_ATTR_WIPHY_BANDS,
+
+	NL80211_ATTR_MNTR_FLAGS,
+
 	/* add attributes here, update the policy in nl80211.c */
 
 	__NL80211_ATTR_AFTER_LAST,
 	NL80211_ATTR_MAX = __NL80211_ATTR_AFTER_LAST - 1
 };
 
+#define NL80211_MAX_SUPP_RATES	32
+
 /**
  * enum nl80211_iftype - (virtual) interface types
  *
@@ -126,4 +244,139 @@ enum nl80211_iftype {
 	NL80211_IFTYPE_MAX = __NL80211_IFTYPE_AFTER_LAST - 1
 };
 
+/**
+ * enum nl80211_sta_flags - station flags
+ *
+ * Station flags. When a station is added to an AP interface, it is
+ * assumed to be already associated (and hence authenticated.)
+ *
+ * @NL80211_STA_FLAG_AUTHORIZED: station is authorized (802.1X)
+ * @NL80211_STA_FLAG_SHORT_PREAMBLE: station is capable of receiving frames
+ *	with short barker preamble
+ * @NL80211_STA_FLAG_WME: station is WME/QoS capable
+ */
+enum nl80211_sta_flags {
+	__NL80211_STA_FLAG_INVALID,
+	NL80211_STA_FLAG_AUTHORIZED,
+	NL80211_STA_FLAG_SHORT_PREAMBLE,
+	NL80211_STA_FLAG_WME,
+
+	/* keep last */
+	__NL80211_STA_FLAG_AFTER_LAST,
+	NL80211_STA_FLAG_MAX = __NL80211_STA_FLAG_AFTER_LAST - 1
+};
+
+/**
+ * enum nl80211_sta_stats - station statistics
+ *
+ * These attribute types are used with %NL80211_ATTR_STA_STATS
+ * when getting information about a station.
+ *
+ * @__NL80211_STA_STAT_INVALID: attribute number 0 is reserved
+ * @NL80211_STA_STAT_INACTIVE_TIME: time since last activity (u32, msecs)
+ * @NL80211_STA_STAT_RX_BYTES: total received bytes (u32, from this station)
+ * @NL80211_STA_STAT_TX_BYTES: total transmitted bytes (u32, to this station)
+ * @__NL80211_STA_STAT_AFTER_LAST: internal
+ * @NL80211_STA_STAT_MAX: highest possible station stats attribute
+ */
+enum nl80211_sta_stats {
+	__NL80211_STA_STAT_INVALID,
+	NL80211_STA_STAT_INACTIVE_TIME,
+	NL80211_STA_STAT_RX_BYTES,
+	NL80211_STA_STAT_TX_BYTES,
+
+	/* keep last */
+	__NL80211_STA_STAT_AFTER_LAST,
+	NL80211_STA_STAT_MAX = __NL80211_STA_STAT_AFTER_LAST - 1
+};
+
+/**
+ * enum nl80211_band_attr - band attributes
+ * @__NL80211_BAND_ATTR_INVALID: attribute number 0 is reserved
+ * @NL80211_BAND_ATTR_FREQS: supported frequencies in this band,
+ *	an array of nested frequency attributes
+ * @NL80211_BAND_ATTR_RATES: supported bitrates in this band,
+ *	an array of nested bitrate attributes
+ */
+enum nl80211_band_attr {
+	__NL80211_BAND_ATTR_INVALID,
+	NL80211_BAND_ATTR_FREQS,
+	NL80211_BAND_ATTR_RATES,
+
+	/* keep last */
+	__NL80211_BAND_ATTR_AFTER_LAST,
+	NL80211_BAND_ATTR_MAX = __NL80211_BAND_ATTR_AFTER_LAST - 1
+};
+
+/**
+ * enum nl80211_frequency_attr - frequency attributes
+ * @NL80211_FREQUENCY_ATTR_FREQ: Frequency in MHz
+ * @NL80211_FREQUENCY_ATTR_DISABLED: Channel is disabled in current
+ *	regulatory domain.
+ * @NL80211_FREQUENCY_ATTR_PASSIVE_SCAN: Only passive scanning is
+ *	permitted on this channel in current regulatory domain.
+ * @NL80211_FREQUENCY_ATTR_NO_IBSS: IBSS networks are not permitted
+ *	on this channel in current regulatory domain.
+ * @NL80211_FREQUENCY_ATTR_RADAR: Radar detection is mandatory
+ *	on this channel in current regulatory domain.
+ */
+enum nl80211_frequency_attr {
+	__NL80211_FREQUENCY_ATTR_INVALID,
+	NL80211_FREQUENCY_ATTR_FREQ,
+	NL80211_FREQUENCY_ATTR_DISABLED,
+	NL80211_FREQUENCY_ATTR_PASSIVE_SCAN,
+	NL80211_FREQUENCY_ATTR_NO_IBSS,
+	NL80211_FREQUENCY_ATTR_RADAR,
+
+	/* keep last */
+	__NL80211_FREQUENCY_ATTR_AFTER_LAST,
+	NL80211_FREQUENCY_ATTR_MAX = __NL80211_FREQUENCY_ATTR_AFTER_LAST - 1
+};
+
+/**
+ * enum nl80211_bitrate_attr - bitrate attributes
+ * @NL80211_BITRATE_ATTR_RATE: Bitrate in units of 100 kbps
+ * @NL80211_BITRATE_ATTR_2GHZ_SHORTPREAMBLE: Short preamble supported
+ *	in 2.4 GHz band.
+ */
+enum nl80211_bitrate_attr {
+	__NL80211_BITRATE_ATTR_INVALID,
+	NL80211_BITRATE_ATTR_RATE,
+	NL80211_BITRATE_ATTR_2GHZ_SHORTPREAMBLE,
+
+	/* keep last */
+	__NL80211_BITRATE_ATTR_AFTER_LAST,
+	NL80211_BITRATE_ATTR_MAX = __NL80211_BITRATE_ATTR_AFTER_LAST - 1
+};
+
+/**
+ * enum nl80211_mntr_flags - monitor configuration flags
+ *
+ * Monitor configuration flags.
+ *
+ * @__NL80211_MNTR_FLAG_INVALID: reserved
+ *
+ * @NL80211_MNTR_FLAG_FCSFAIL: pass frames with bad FCS
+ * @NL80211_MNTR_FLAG_PLCPFAIL: pass frames with bad PLCP
+ * @NL80211_MNTR_FLAG_CONTROL: pass control frames
+ * @NL80211_MNTR_FLAG_OTHER_BSS: disable BSSID filtering
+ * @NL80211_MNTR_FLAG_COOK_FRAMES: report frames after processing.
+ *	overrides all other flags.
+ *
+ * @__NL80211_MNTR_FLAG_AFTER_LAST: internal use
+ * @NL80211_MNTR_FLAG_MAX: highest possible monitor flag
+ */
+enum nl80211_mntr_flags {
+	__NL80211_MNTR_FLAG_INVALID,
+	NL80211_MNTR_FLAG_FCSFAIL,
+	NL80211_MNTR_FLAG_PLCPFAIL,
+	NL80211_MNTR_FLAG_CONTROL,
+	NL80211_MNTR_FLAG_OTHER_BSS,
+	NL80211_MNTR_FLAG_COOK_FRAMES,
+
+	/* keep last */
+	__NL80211_MNTR_FLAG_AFTER_LAST,
+	NL80211_MNTR_FLAG_MAX = __NL80211_MNTR_FLAG_AFTER_LAST - 1
+};
+
 #endif /* __LINUX_NL80211_H */
diff --git a/package/mac80211/src/include/net/cfg80211.h b/package/mac80211/src/include/net/cfg80211.h
index d30960e175..ab4caf6395 100644
--- a/package/mac80211/src/include/net/cfg80211.h
+++ b/package/mac80211/src/include/net/cfg80211.h
@@ -49,6 +49,140 @@ extern int ieee80211_radiotap_iterator_next(
    struct ieee80211_radiotap_iterator *iterator);
 
 
+ /**
+ * struct key_params - key information
+ *
+ * Information about a key
+ *
+ * @key: key material
+ * @key_len: length of key material
+ * @cipher: cipher suite selector
+ * @seq: sequence counter (IV/PN) for TKIP and CCMP keys, only used
+ *	with the get_key() callback, must be in little endian,
+ *	length given by @seq_len.
+ */
+struct key_params {
+	u8 *key;
+	u8 *seq;
+	int key_len;
+	int seq_len;
+	u32 cipher;
+};
+
+/**
+ * struct beacon_parameters - beacon parameters
+ *
+ * Used to configure the beacon for an interface.
+ *
+ * @head: head portion of beacon (before TIM IE)
+ *     or %NULL if not changed
+ * @tail: tail portion of beacon (after TIM IE)
+ *     or %NULL if not changed
+ * @interval: beacon interval or zero if not changed
+ * @dtim_period: DTIM period or zero if not changed
+ * @head_len: length of @head
+ * @tail_len: length of @tail
+ */
+struct beacon_parameters {
+	u8 *head, *tail;
+	int interval, dtim_period;
+	int head_len, tail_len;
+};
+
+/**
+ * enum station_flags - station flags
+ *
+ * Station capability flags. Note that these must be the bits
+ * according to the nl80211 flags.
+ *
+ * @STATION_FLAG_CHANGED: station flags were changed
+ * @STATION_FLAG_AUTHORIZED: station is authorized to send frames (802.1X)
+ * @STATION_FLAG_SHORT_PREAMBLE: station is capable of receiving frames
+ *	with short preambles
+ * @STATION_FLAG_WME: station is WME/QoS capable
+ */
+enum station_flags {
+	STATION_FLAG_CHANGED		= 1<<0,
+	STATION_FLAG_AUTHORIZED		= 1<<NL80211_STA_FLAG_AUTHORIZED,
+	STATION_FLAG_SHORT_PREAMBLE	= 1<<NL80211_STA_FLAG_SHORT_PREAMBLE,
+	STATION_FLAG_WME		= 1<<NL80211_STA_FLAG_WME,
+};
+
+/**
+ * struct station_parameters - station parameters
+ *
+ * Used to change and create a new station.
+ *
+ * @vlan: vlan interface station should belong to
+ * @supported_rates: supported rates in IEEE 802.11 format
+ *	(or NULL for no change)
+ * @supported_rates_len: number of supported rates
+ * @station_flags: station flags (see &enum station_flags)
+ * @listen_interval: listen interval or -1 for no change
+ * @aid: AID or zero for no change
+ */
+struct station_parameters {
+	u8 *supported_rates;
+	struct net_device *vlan;
+	u32 station_flags;
+	int listen_interval;
+	u16 aid;
+	u8 supported_rates_len;
+};
+
+/**
+ * enum station_stats_flags - station statistics flags
+ *
+ * Used by the driver to indicate which info in &struct station_stats
+ * it has filled in during get_station().
+ *
+ * @STATION_STAT_INACTIVE_TIME: @inactive_time filled
+ * @STATION_STAT_RX_BYTES: @rx_bytes filled
+ * @STATION_STAT_TX_BYTES: @tx_bytes filled
+ */
+enum station_stats_flags {
+	STATION_STAT_INACTIVE_TIME	= 1<<0,
+	STATION_STAT_RX_BYTES		= 1<<1,
+	STATION_STAT_TX_BYTES		= 1<<2,
+};
+
+/**
+ * struct station_stats - station statistics
+ *
+ * Station information filled by driver for get_station().
+ *
+ * @filled: bitflag of flags from &enum station_stats_flags
+ * @inactive_time: time since last station activity (tx/rx) in milliseconds
+ * @rx_bytes: bytes received from this station
+ * @tx_bytes: bytes transmitted to this station
+ */
+struct station_stats {
+	u32 filled;
+	u32 inactive_time;
+	u32 rx_bytes;
+	u32 tx_bytes;
+};
+
+/**
+ * enum monitor_flags - monitor flags
+ *
+ * Monitor interface configuration flags. Note that these must be the bits
+ * according to the nl80211 flags.
+ *
+ * @MONITOR_FLAG_FCSFAIL: pass frames with bad FCS
+ * @MONITOR_FLAG_PLCPFAIL: pass frames with bad PLCP
+ * @MONITOR_FLAG_CONTROL: pass control frames
+ * @MONITOR_FLAG_OTHER_BSS: disable BSSID filtering
+ * @MONITOR_FLAG_COOK_FRAMES: report frames after processing
+ */
+enum monitor_flags {
+	MONITOR_FLAG_FCSFAIL		= 1<<NL80211_MNTR_FLAG_FCSFAIL,
+	MONITOR_FLAG_PLCPFAIL		= 1<<NL80211_MNTR_FLAG_PLCPFAIL,
+	MONITOR_FLAG_CONTROL		= 1<<NL80211_MNTR_FLAG_CONTROL,
+	MONITOR_FLAG_OTHER_BSS		= 1<<NL80211_MNTR_FLAG_OTHER_BSS,
+	MONITOR_FLAG_COOK_FRAMES	= 1<<NL80211_MNTR_FLAG_COOK_FRAMES,
+};
+
 /* from net/wireless.h */
 struct wiphy;
 
@@ -71,13 +205,66 @@ struct wiphy;
  *
  * @change_virtual_intf: change type of virtual interface
  *
+ * @add_key: add a key with the given parameters. @mac_addr will be %NULL
+ *	when adding a group key.
+ *
+ * @get_key: get information about the key with the given parameters.
+ *	@mac_addr will be %NULL when requesting information for a group
+ *	key. All pointers given to the @callback function need not be valid
+ *	after it returns.
+ *
+ * @del_key: remove a key given the @mac_addr (%NULL for a group key)
+ *	and @key_index
+ *
+ * @set_default_key: set the default key on an interface
+ *
+ * @add_beacon: Add a beacon with given parameters, @head, @interval
+ *	and @dtim_period will be valid, @tail is optional.
+ * @set_beacon: Change the beacon parameters for an access point mode
+ *	interface. This should reject the call when no beacon has been
+ *	configured.
+ * @del_beacon: Remove beacon configuration and stop sending the beacon.
+ *
+ * @add_station: Add a new station.
+ *
+ * @del_station: Remove a station; @mac may be NULL to remove all stations.
+ *
+ * @change_station: Modify a given station.
  */
 struct cfg80211_ops {
 	int	(*add_virtual_intf)(struct wiphy *wiphy, char *name,
-				    enum nl80211_iftype type);
+				    enum nl80211_iftype type, u32 *flags);
 	int	(*del_virtual_intf)(struct wiphy *wiphy, int ifindex);
 	int	(*change_virtual_intf)(struct wiphy *wiphy, int ifindex,
-				       enum nl80211_iftype type);
+				       enum nl80211_iftype type, u32 *flags);
+
+	int	(*add_key)(struct wiphy *wiphy, struct net_device *netdev,
+			   u8 key_index, u8 *mac_addr,
+			   struct key_params *params);
+	int	(*get_key)(struct wiphy *wiphy, struct net_device *netdev,
+			   u8 key_index, u8 *mac_addr, void *cookie,
+			   void (*callback)(void *cookie, struct key_params*));
+	int	(*del_key)(struct wiphy *wiphy, struct net_device *netdev,
+			   u8 key_index, u8 *mac_addr);
+	int	(*set_default_key)(struct wiphy *wiphy,
+				   struct net_device *netdev,
+				   u8 key_index);
+
+	int	(*add_beacon)(struct wiphy *wiphy, struct net_device *dev,
+			      struct beacon_parameters *info);
+	int	(*set_beacon)(struct wiphy *wiphy, struct net_device *dev,
+			      struct beacon_parameters *info);
+	int	(*del_beacon)(struct wiphy *wiphy, struct net_device *dev);
+
+
+	int	(*add_station)(struct wiphy *wiphy, struct net_device *dev,
+			       u8 *mac, struct station_parameters *params);
+	int	(*del_station)(struct wiphy *wiphy, struct net_device *dev,
+			       u8 *mac);
+	int	(*change_station)(struct wiphy *wiphy, struct net_device *dev,
+				  u8 *mac, struct station_parameters *params);
+	int	(*get_station)(struct wiphy *wiphy, struct net_device *dev,
+			       u8 *mac, struct station_stats *stats);
 };
 
 #endif /* __NET_CFG80211_H */
diff --git a/package/mac80211/src/include/net/mac80211.h b/package/mac80211/src/include/net/mac80211.h
index 2b1bffbf5e..460da54a00 100644
--- a/package/mac80211/src/include/net/mac80211.h
+++ b/package/mac80211/src/include/net/mac80211.h
@@ -69,95 +69,20 @@
  * not do so then mac80211 may add this under certain circumstances.
  */
 
-#define IEEE80211_CHAN_W_SCAN 0x00000001
-#define IEEE80211_CHAN_W_ACTIVE_SCAN 0x00000002
-#define IEEE80211_CHAN_W_IBSS 0x00000004
-
-/* Channel information structure. Low-level driver is expected to fill in chan,
- * freq, and val fields. Other fields will be filled in by 80211.o based on
- * hostapd information and low-level driver does not need to use them. The
- * limits for each channel will be provided in 'struct ieee80211_conf' when
- * configuring the low-level driver with hw->config callback. If a device has
- * a default regulatory domain, IEEE80211_HW_DEFAULT_REG_DOMAIN_CONFIGURED
- * can be set to let the driver configure all fields */
-struct ieee80211_channel {
-	short chan; /* channel number (IEEE 802.11) */
-	short freq; /* frequency in MHz */
-	int val; /* hw specific value for the channel */
-	int flag; /* flag for hostapd use (IEEE80211_CHAN_*) */
-	unsigned char power_level;
-	unsigned char antenna_max;
-};
-
-#define IEEE80211_RATE_ERP 0x00000001
-#define IEEE80211_RATE_BASIC 0x00000002
-#define IEEE80211_RATE_PREAMBLE2 0x00000004
-#define IEEE80211_RATE_SUPPORTED 0x00000010
-#define IEEE80211_RATE_OFDM 0x00000020
-#define IEEE80211_RATE_CCK 0x00000040
-#define IEEE80211_RATE_MANDATORY 0x00000100
-
-#define IEEE80211_RATE_CCK_2 (IEEE80211_RATE_CCK | IEEE80211_RATE_PREAMBLE2)
-#define IEEE80211_RATE_MODULATION(f) \
-	(f & (IEEE80211_RATE_CCK | IEEE80211_RATE_OFDM))
-
-/* Low-level driver should set PREAMBLE2, OFDM and CCK flags.
- * BASIC, SUPPORTED, ERP, and MANDATORY flags are set in 80211.o based on the
- * configuration. */
-struct ieee80211_rate {
-	int rate; /* rate in 100 kbps */
-	int val; /* hw specific value for the rate */
-	int flags; /* IEEE80211_RATE_ flags */
-	int val2; /* hw specific value for the rate when using short preamble
-		   * (only when IEEE80211_RATE_PREAMBLE2 flag is set, i.e., for
-		   * 2, 5.5, and 11 Mbps) */
-	signed char min_rssi_ack;
-	unsigned char min_rssi_ack_delta;
-
-	/* following fields are set by 80211.o and need not be filled by the
-	 * low-level driver */
-	int rate_inv; /* inverse of the rate (LCM(all rates) / rate) for
-		       * optimizing channel utilization estimates */
-};
-
 /**
- * enum ieee80211_phymode - PHY modes
+ * struct ieee80211_ht_bss_info - describing BSS's HT characteristics
  *
- * @MODE_IEEE80211A: 5GHz as defined by 802.11a/802.11h
- * @MODE_IEEE80211B: 2.4 GHz as defined by 802.11b
- * @MODE_IEEE80211G: 2.4 GHz as defined by 802.11g (with OFDM),
- *	backwards compatible with 11b mode
- * @NUM_IEEE80211_MODES: internal
- */
-enum ieee80211_phymode {
-	MODE_IEEE80211A,
-	MODE_IEEE80211B,
-	MODE_IEEE80211G,
-
-	/* keep last */
-	NUM_IEEE80211_MODES
-};
-
-/**
- * struct ieee80211_hw_mode - PHY mode definition
- *
- * This structure describes the capabilities supported by the device
- * in a single PHY mode.
+ * This structure describes most essential parameters needed
+ * to describe 802.11n HT characteristics in a BSS
  *
- * @mode: the PHY mode for this definition
- * @num_channels: number of supported channels
- * @channels: pointer to array of supported channels
- * @num_rates: number of supported bitrates
- * @rates: pointer to array of supported bitrates
- * @list: internal
+ * @primary_channel: channel number of primery channel
+ * @bss_cap: 802.11n's general BSS capabilities (e.g. channel width)
+ * @bss_op_mode: 802.11n's BSS operation modes (e.g. HT protection)
  */
-struct ieee80211_hw_mode {
-	struct list_head list;
-	struct ieee80211_channel *channels;
-	struct ieee80211_rate *rates;
-	enum ieee80211_phymode mode;
-	int num_channels;
-	int num_rates;
+struct ieee80211_ht_bss_info {
+	u8 primary_channel;
+	u8 bss_cap;  /* use IEEE80211_HT_IE_CHA_ */
+	u8 bss_op_mode; /* use IEEE80211_HT_IE_ */
 };
 
 /**
@@ -208,6 +133,7 @@ struct ieee80211_tx_queue_stats_data {
  * @IEEE80211_TX_QUEUE_AFTER_BEACON: transmit queue for frames to be
  *	sent after a beacon
  * @IEEE80211_TX_QUEUE_BEACON: transmit queue for beacon frames
+ * @NUM_TX_DATA_QUEUES_AMPDU: adding more queues for A-MPDU
  */
 enum ieee80211_tx_queue {
 	IEEE80211_TX_QUEUE_DATA0,
@@ -223,11 +149,12 @@ enum ieee80211_tx_queue {
  * this struct need to have fixed values. As soon as it is removed, we can
  * fix these entries. */
 	IEEE80211_TX_QUEUE_AFTER_BEACON = 6,
-	IEEE80211_TX_QUEUE_BEACON = 7
+	IEEE80211_TX_QUEUE_BEACON = 7,
+	NUM_TX_DATA_QUEUES_AMPDU = 16
 };
 
 struct ieee80211_tx_queue_stats {
-	struct ieee80211_tx_queue_stats_data data[NUM_TX_DATA_QUEUES];
+	struct ieee80211_tx_queue_stats_data data[NUM_TX_DATA_QUEUES_AMPDU];
 };
 
 struct ieee80211_low_level_stats {
@@ -237,16 +164,56 @@ struct ieee80211_low_level_stats {
 	unsigned int dot11RTSSuccessCount;
 };
 
+/**
+ * enum ieee80211_bss_change - BSS change notification flags
+ *
+ * These flags are used with the bss_info_changed() callback
+ * to indicate which BSS parameter changed.
+ *
+ * @BSS_CHANGED_ASSOC: association status changed (associated/disassociated),
+ *	also implies a change in the AID.
+ * @BSS_CHANGED_ERP_CTS_PROT: CTS protection changed
+ * @BSS_CHANGED_ERP_PREAMBLE: preamble changed
+ */
+enum ieee80211_bss_change {
+	BSS_CHANGED_ASSOC		= 1<<0,
+	BSS_CHANGED_ERP_CTS_PROT	= 1<<1,
+	BSS_CHANGED_ERP_PREAMBLE	= 1<<2,
+};
+
+/**
+ * struct ieee80211_bss_conf - holds the BSS's changing parameters
+ *
+ * This structure keeps information about a BSS (and an association
+ * to that BSS) that can change during the lifetime of the BSS.
+ *
+ * @assoc: association status
+ * @aid: association ID number, valid only when @assoc is true
+ * @use_cts_prot: use CTS protection
+ * @use_short_preamble: use 802.11b short preamble
+ */
+struct ieee80211_bss_conf {
+	/* association related data */
+	bool assoc;
+	u16 aid;
+	/* erp related data */
+	bool use_cts_prot;
+	bool use_short_preamble;
+};
+
 /* Transmit control fields. This data structure is passed to low-level driver
  * with each TX frame. The low-level driver is responsible for configuring
  * the hardware to use given values (depending on what is supported). */
 
 struct ieee80211_tx_control {
-	int tx_rate; /* Transmit rate, given as the hw specific value for the
-		      * rate (from struct ieee80211_rate) */
-	int rts_cts_rate; /* Transmit rate for RTS/CTS frame, given as the hw
-			   * specific value for the rate (from
-			   * struct ieee80211_rate) */
+	struct ieee80211_vif *vif;
+	struct ieee80211_rate *tx_rate;
+
+	/* Transmit rate for RTS/CTS frame */
+	struct ieee80211_rate *rts_cts_rate;
+
+	/* retry rate for the last retries */
+	struct ieee80211_rate *alt_retry_rate;
 
 #define IEEE80211_TXCTL_REQ_TX_STATUS	(1<<0)/* request TX status callback for
 						* this frame */
@@ -265,10 +232,16 @@ struct ieee80211_tx_control {
 #define IEEE80211_TXCTL_REQUEUE		(1<<7)
 #define IEEE80211_TXCTL_FIRST_FRAGMENT	(1<<8) /* this is a first fragment of
 						* the frame */
+#define IEEE80211_TXCTL_SHORT_PREAMBLE	(1<<9)
 #define IEEE80211_TXCTL_LONG_RETRY_LIMIT (1<<10) /* this frame should be send
 						  * using the through
 						  * set_retry_limit configured
 						  * long retry value */
+#define IEEE80211_TXCTL_EAPOL_FRAME	(1<<11) /* internal to mac80211 */
+#define IEEE80211_TXCTL_SEND_AFTER_DTIM	(1<<12) /* send this frame after DTIM
+						 * beacon */
+#define IEEE80211_TXCTL_AMPDU		(1<<13) /* this frame should be sent
+						 * as part of an A-MPDU */
 	u32 flags;			       /* tx control flags defined
 						* above */
 	u8 key_idx;		/* keyidx from hw->set_key(), undefined if
@@ -276,22 +249,12 @@ struct ieee80211_tx_control {
 	u8 retry_limit;		/* 1 = only first attempt, 2 = one retry, ..
 				 * This could be used when set_retry_limit
 				 * is not implemented by the driver */
-	u8 power_level;		/* per-packet transmit power level, in dBm */
 	u8 antenna_sel_tx; 	/* 0 = default/diversity, 1 = Ant0, 2 = Ant1 */
 	u8 icv_len;		/* length of the ICV/MIC field in octets */
 	u8 iv_len;		/* length of the IV field in octets */
 	u8 queue;		/* hardware queue to use for this frame;
 				 * 0 = highest, hw->queues-1 = lowest */
-	struct ieee80211_rate *rate;		/* internal 80211.o rate */
-	struct ieee80211_rate *rts_rate;	/* internal 80211.o rate
-						 * for RTS/CTS */
-	int alt_retry_rate; /* retry rate for the last retries, given as the
-			     * hw specific value for the rate (from
-			     * struct ieee80211_rate). To be used to limit
-			     * packet dropping when probing higher rates, if hw
-			     * supports multiple retry rates. -1 = not used */
 	int type;	/* internal */
-	int ifindex;	/* internal */
 };
 
 
@@ -312,6 +275,8 @@ struct ieee80211_tx_control {
  *	the frame.
  * @RX_FLAG_FAILED_PLCP_CRC: Set this flag if the PCLP check failed on
  *	the frame.
+ * @RX_FLAG_TSFT: The timestamp passed in the RX status (@mactime field)
+ *	is valid.
  */
 enum mac80211_rx_flags {
 	RX_FLAG_MMIC_ERROR	= 1<<0,
@@ -321,6 +286,7 @@ enum mac80211_rx_flags {
 	RX_FLAG_IV_STRIPPED	= 1<<4,
 	RX_FLAG_FAILED_FCS_CRC	= 1<<5,
 	RX_FLAG_FAILED_PLCP_CRC = 1<<6,
+	RX_FLAG_TSFT		= 1<<7,
 };
 
 /**
@@ -330,26 +296,24 @@ enum mac80211_rx_flags {
  * supported by hardware) to the 802.11 code with each received
  * frame.
  * @mactime: MAC timestamp as defined by 802.11
+ * @band: the active band when this frame was received
  * @freq: frequency the radio was tuned to when receiving this frame, in MHz
- * @channel: channel the radio was tuned to
- * @phymode: active PHY mode
  * @ssi: signal strength when receiving this frame
  * @signal: used as 'qual' in statistics reporting
  * @noise: PHY noise when receiving this frame
  * @antenna: antenna used
- * @rate: data rate
+ * @rate_idx: index of data rate into band's supported rates
  * @flag: %RX_FLAG_*
  */
 struct ieee80211_rx_status {
 	u64 mactime;
+	enum ieee80211_band band;
 	int freq;
-	int channel;
-	enum ieee80211_phymode phymode;
 	int ssi;
 	int signal;
 	int noise;
 	int antenna;
-	int rate;
+	int rate_idx;
 	int flag;
 };
 
@@ -360,12 +324,14 @@ struct ieee80211_rx_status {
  *
  * @IEEE80211_TX_STATUS_TX_FILTERED: The frame was not transmitted
  *	because the destination STA was in powersave mode.
- *
  * @IEEE80211_TX_STATUS_ACK: Frame was acknowledged
+ * @IEEE80211_TX_STATUS_AMPDU: The frame was aggregated, so status
+ * 	is for the whole aggregation.
  */
 enum ieee80211_tx_status_flags {
 	IEEE80211_TX_STATUS_TX_FILTERED	= 1<<0,
 	IEEE80211_TX_STATUS_ACK		= 1<<1,
+	IEEE80211_TX_STATUS_AMPDU	= 1<<2,
 };
 
 /**
@@ -376,24 +342,25 @@ enum ieee80211_tx_status_flags {
  *
  * @control: a copy of the &struct ieee80211_tx_control passed to the driver
  *	in the tx() callback.
- *
  * @flags: transmit status flags, defined above
- *
- * @ack_signal: signal strength of the ACK frame
- *
+ * @retry_count: number of retries
  * @excessive_retries: set to 1 if the frame was retried many times
  *	but not acknowledged
- *
- * @retry_count: number of retries
- *
+ * @ampdu_ack_len: number of aggregated frames.
+ * 	relevant only if IEEE80211_TX_STATUS_AMPDU was set.
+ * @ampdu_ack_map: block ack bit map for the aggregation.
+ * 	relevant only if IEEE80211_TX_STATUS_AMPDU was set.
+ * @ack_signal: signal strength of the ACK frame
  * @queue_length: ?? REMOVE
  * @queue_number: ?? REMOVE
  */
 struct ieee80211_tx_status {
 	struct ieee80211_tx_control control;
 	u8 flags;
-	bool excessive_retries;
 	u8 retry_count;
+	bool excessive_retries;
+	u8 ampdu_ack_len;
+	u64 ampdu_ack_map;
 	int ack_signal;
 	int queue_length;
 	int queue_number;
@@ -406,11 +373,12 @@ struct ieee80211_tx_status {
  *
  * @IEEE80211_CONF_SHORT_SLOT_TIME: use 802.11g short slot time
  * @IEEE80211_CONF_RADIOTAP: add radiotap header at receive time (if supported)
- *
+ * @IEEE80211_CONF_SUPPORT_HT_MODE: use 802.11n HT capabilities (if supported)
  */
 enum ieee80211_conf_flags {
-	IEEE80211_CONF_SHORT_SLOT_TIME	= 1<<0,
-	IEEE80211_CONF_RADIOTAP		= 1<<1,
+	IEEE80211_CONF_SHORT_SLOT_TIME	= (1<<0),
+	IEEE80211_CONF_RADIOTAP		= (1<<1),
+	IEEE80211_CONF_SUPPORT_HT_MODE	= (1<<2),
 };
 
 /**
@@ -420,38 +388,32 @@ enum ieee80211_conf_flags {
  *
  * @radio_enabled: when zero, driver is required to switch off the radio.
  *	TODO make a flag
- * @channel: IEEE 802.11 channel number
- * @freq: frequency in MHz
- * @channel_val: hardware specific channel value for the channel
- * @phymode: PHY mode to activate (REMOVE)
- * @chan: channel to switch to, pointer to the channel information
- * @mode: pointer to mode definition
- * @regulatory_domain: ??
  * @beacon_int: beacon interval (TODO make interface config)
  * @flags: configuration flags defined above
- * @power_level: transmit power limit for current regulatory domain in dBm
- * @antenna_max: maximum antenna gain
+ * @power_level: requested transmit power (in dBm)
+ * @max_antenna_gain: maximum antenna gain (in dBi)
  * @antenna_sel_tx: transmit antenna selection, 0: default/diversity,
  *	1/2: antenna 0/1
  * @antenna_sel_rx: receive antenna selection, like @antenna_sel_tx
+ * @ht_conf: describes current self configuration of 802.11n HT capabilies
+ * @ht_bss_conf: describes current BSS configuration of 802.11n HT parameters
+ * @channel: the channel to tune to
  */
 struct ieee80211_conf {
-	int channel;			/* IEEE 802.11 channel number */
-	int freq;			/* MHz */
-	int channel_val;		/* hw specific value for the channel */
-
-	enum ieee80211_phymode phymode;
-	struct ieee80211_channel *chan;
-	struct ieee80211_hw_mode *mode;
 	unsigned int regulatory_domain;
 	int radio_enabled;
 
 	int beacon_int;
 	u32 flags;
-	u8 power_level;
-	u8 antenna_max;
+	int power_level;
+	int max_antenna_gain;
 	u8 antenna_sel_tx;
 	u8 antenna_sel_rx;
+
+	struct ieee80211_channel *channel;
+
+	struct ieee80211_ht_info ht_conf;
+	struct ieee80211_ht_bss_info ht_bss_conf;
 };
 
 /**
@@ -479,14 +441,28 @@ enum ieee80211_if_types {
 	IEEE80211_IF_TYPE_VLAN,
 };
 
+/**
+ * struct ieee80211_vif - per-interface data
+ *
+ * Data in this structure is continually present for driver
+ * use during the life of a virtual interface.
+ *
+ * @type: type of this virtual interface
+ * @drv_priv: data area for driver use, will always be aligned to
+ *	sizeof(void *).
+ */
+struct ieee80211_vif {
+	enum ieee80211_if_types type;
+	/* must be last */
+	u8 drv_priv[0] __attribute__((__aligned__(sizeof(void *))));
+};
+
 /**
  * struct ieee80211_if_init_conf - initial configuration of an interface
  *
- * @if_id: internal interface ID. This number has no particular meaning to
- *	drivers and the only allowed usage is to pass it to
- *	ieee80211_beacon_get() and ieee80211_get_buffered_bc() functions.
- *	This field is not valid for monitor interfaces
- *	(interfaces of %IEEE80211_IF_TYPE_MNTR type).
+ * @vif: pointer to a driver-use per-interface structure. The pointer
+ *	itself is also used for various functions including
+ *	ieee80211_beacon_get() and ieee80211_get_buffered_bc().
  * @type: one of &enum ieee80211_if_types constants. Determines the type of
  *	added/removed interface.
  * @mac_addr: pointer to MAC address of the interface. This pointer is valid
@@ -503,8 +479,8 @@ enum ieee80211_if_types {
  * in pure monitor mode.
  */
 struct ieee80211_if_init_conf {
-	int if_id;
 	enum ieee80211_if_types type;
+	struct ieee80211_vif *vif;
 	void *mac_addr;
 };
 
@@ -597,9 +573,6 @@ struct ieee80211_key_conf {
 	u8 key[0];
 };
 
-#define IEEE80211_SEQ_COUNTER_RX	0
-#define IEEE80211_SEQ_COUNTER_TX	1
-
 /**
  * enum set_key_cmd - key command
  *
@@ -659,15 +632,19 @@ enum sta_notify_cmd {
  *	%IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE is also not set because
  *	otherwise the stack will not know when the DTIM beacon was sent.
  *
- * @IEEE80211_HW_DEFAULT_REG_DOMAIN_CONFIGURED:
- *	Channels are already configured to the default regulatory domain
- *	specified in the device's EEPROM
+ * @IEEE80211_HW_2GHZ_SHORT_SLOT_INCAPABLE:
+ *	Hardware is not capable of short slot operation on the 2.4 GHz band.
+ *
+ * @IEEE80211_HW_2GHZ_SHORT_PREAMBLE_INCAPABLE:
+ *	Hardware is not capable of receiving frames with short preamble on
+ *	the 2.4 GHz band.
  */
 enum ieee80211_hw_flags {
 	IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE		= 1<<0,
 	IEEE80211_HW_RX_INCLUDES_FCS			= 1<<1,
 	IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING	= 1<<2,
-	IEEE80211_HW_DEFAULT_REG_DOMAIN_CONFIGURED	= 1<<3,
+	IEEE80211_HW_2GHZ_SHORT_SLOT_INCAPABLE		= 1<<3,
+	IEEE80211_HW_2GHZ_SHORT_PREAMBLE_INCAPABLE	= 1<<4,
 };
 
 /**
@@ -679,7 +656,8 @@ enum ieee80211_hw_flags {
  * @wiphy: This points to the &struct wiphy allocated for this
  *	802.11 PHY. You must fill in the @perm_addr and @dev
  *	members of this structure using SET_IEEE80211_DEV()
- *	and SET_IEEE80211_PERM_ADDR().
+ *	and SET_IEEE80211_PERM_ADDR(). Additionally, all supported
+ *	bands (with channels, bitrates) are registered here.
  *
  * @conf: &struct ieee80211_conf, device configuration, don't use.
  *
@@ -706,15 +684,24 @@ enum ieee80211_hw_flags {
  *
  * @queues: number of available hardware transmit queues for
  *	data packets. WMM/QoS requires at least four.
+ *
+ * @rate_control_algorithm: rate control algorithm for this hardware.
+ *	If unset (NULL), the default algorithm will be used. Must be
+ *	set before calling ieee80211_register_hw().
+ *
+ * @vif_data_size: size (in bytes) of the drv_priv data area
+ *	within &struct ieee80211_vif.
  */
 struct ieee80211_hw {
 	struct ieee80211_conf conf;
 	struct wiphy *wiphy;
 	struct workqueue_struct *workqueue;
+	const char *rate_control_algorithm;
 	void *priv;
 	u32 flags;
 	unsigned int extra_tx_headroom;
 	int channel_change_time;
+	int vif_data_size;
 	u8 queues;
 	s8 max_rssi;
 	s8 max_signal;
@@ -854,19 +841,22 @@ enum ieee80211_filter_flags {
 };
 
 /**
- * enum ieee80211_erp_change_flags - erp change flags
- *
- * These flags are used with the erp_ie_changed() callback in
- * &struct ieee80211_ops to indicate which parameter(s) changed.
- * @IEEE80211_ERP_CHANGE_PROTECTION: protection changed
- * @IEEE80211_ERP_CHANGE_PREAMBLE: barker preamble mode changed
+ * enum ieee80211_ampdu_mlme_action - A-MPDU actions
+ *
+ * These flags are used with the ampdu_action() callback in
+ * &struct ieee80211_ops to indicate which action is needed.
+ * @IEEE80211_AMPDU_RX_START: start Rx aggregation
+ * @IEEE80211_AMPDU_RX_STOP: stop Rx aggregation
+ * @IEEE80211_AMPDU_TX_START: start Tx aggregation
+ * @IEEE80211_AMPDU_TX_STOP: stop Tx aggregation
  */
-enum ieee80211_erp_change_flags {
-	IEEE80211_ERP_CHANGE_PROTECTION	= 1<<0,
-	IEEE80211_ERP_CHANGE_PREAMBLE	= 1<<1,
+enum ieee80211_ampdu_mlme_action {
+	IEEE80211_AMPDU_RX_START,
+	IEEE80211_AMPDU_RX_STOP,
+	IEEE80211_AMPDU_TX_START,
+	IEEE80211_AMPDU_TX_STOP,
 };
 
-
 /**
  * struct ieee80211_ops - callbacks from mac80211 to the driver
  *
@@ -922,6 +912,14 @@ enum ieee80211_erp_change_flags {
  * @config_interface: Handler for configuration requests related to interfaces
  *	(e.g. BSSID changes.)
  *
+ * @bss_info_changed: Handler for configuration requests related to BSS
+ *	parameters that may vary during BSS's lifespan, and may affect low
+ *	level driver (e.g. assoc/disassoc status, erp parameters).
+ *	This function should not be used if no BSS has been set, unless
+ *	for association indication. The @changed parameter indicates which
+ *	of the bss parameters has changed when a call is made. This callback
+ *	has to be atomic.
+ *
  * @configure_filter: Configure the device's RX filter.
  *	See the section "Frame filtering" for more information.
  *	This callback must be implemented and atomic.
@@ -936,30 +934,16 @@ enum ieee80211_erp_change_flags {
  *	and remove_interface calls, i.e. while the interface with the
  *	given local_address is enabled.
  *
- * @set_ieee8021x: Enable/disable IEEE 802.1X. This item requests wlan card
- *	to pass unencrypted EAPOL-Key frames even when encryption is
- *	configured. If the wlan card does not require such a configuration,
- *	this function pointer can be set to NULL.
- *
- * @set_port_auth: Set port authorization state (IEEE 802.1X PAE) to be
- *	authorized (@authorized=1) or unauthorized (=0). This function can be
- *	used if the wlan hardware or low-level driver implements PAE.
- *	mac80211 will filter frames based on authorization state in any case,
- *	so this function pointer can be NULL if low-level driver does not
- *	require event notification about port state changes.
- *
  * @hw_scan: Ask the hardware to service the scan request, no need to start
- *	the scan state machine in stack.
+ *	the scan state machine in stack. The scan must honour the channel
+ *	configuration done by the regulatory agent in the wiphy's registered
+ *	bands.
  *
  * @get_stats: return low-level statistics
  *
- * @set_privacy_invoked: For devices that generate their own beacons and probe
- *	response or association responses this updates the state of privacy_invoked
- *	returns 0 for success or an error number.
- *
- * @get_sequence_counter: For devices that have internal sequence counters this
- *	callback allows mac80211 to access the current value of a counter.
- *	This callback seems not well-defined, tell us if you need it.
+ * @get_tkip_seq: If your device implements TKIP encryption in hardware this
+ *	callback should be provided to read the TKIP transmit IVs (both IV32
+ *	and IV16) for the given key from hardware.
  *
  * @set_rts_threshold: Configuration of RTS threshold (if device needs it)
  *
@@ -972,8 +956,6 @@ enum ieee80211_erp_change_flags {
  * @sta_notify: Notifies low level driver about addition or removal
  *	of assocaited station or AP.
  *
- * @erp_ie_changed: Handle ERP IE change notifications. Must be atomic.
- *
  * @conf_tx: Configure TX queue parameters (EDCF (aifs, cw_min, cw_max),
  *	bursting) for a hardware TX queue. The @queue parameter uses the
  *	%IEEE80211_TX_QUEUE_* constants. Must be atomic.
@@ -1008,6 +990,15 @@ enum ieee80211_erp_change_flags {
  * @tx_last_beacon: Determine whether the last IBSS beacon was sent by us.
  *	This is needed only for IBSS mode and the result of this function is
  *	used to determine whether to reply to Probe Requests.
+ *
+ * @conf_ht: Configures low level driver with 802.11n HT data. Must be atomic.
+ *
+ * @ampdu_action: Perform a certain A-MPDU action
+ * 	The RA/TID combination determines the destination and TID we want
+ * 	the ampdu action to be performed for. The action is defined through
+ * 	ieee80211_ampdu_mlme_action. Starting sequence number (@ssn)
+ * 	is the first frame we expect to perform the action on. notice
+ * 	that TX/RX_STOP can pass NULL for this parameter.
  */
 struct ieee80211_ops {
 	int (*tx)(struct ieee80211_hw *hw, struct sk_buff *skb,
@@ -1020,7 +1011,12 @@ struct ieee80211_ops {
 				 struct ieee80211_if_init_conf *conf);
 	int (*config)(struct ieee80211_hw *hw, struct ieee80211_conf *conf);
 	int (*config_interface)(struct ieee80211_hw *hw,
-				int if_id, struct ieee80211_if_conf *conf);
+				struct ieee80211_vif *vif,
+				struct ieee80211_if_conf *conf);
+	void (*bss_info_changed)(struct ieee80211_hw *hw,
+				 struct ieee80211_vif *vif,
+				 struct ieee80211_bss_conf *info,
+				 u32 changed);
 	void (*configure_filter)(struct ieee80211_hw *hw,
 				 unsigned int changed_flags,
 				 unsigned int *total_flags,
@@ -1029,25 +1025,17 @@ struct ieee80211_ops {
 	int (*set_key)(struct ieee80211_hw *hw, enum set_key_cmd cmd,
 		       const u8 *local_address, const u8 *address,
 		       struct ieee80211_key_conf *key);
-	int (*set_ieee8021x)(struct ieee80211_hw *hw, int use_ieee8021x);
-	int (*set_port_auth)(struct ieee80211_hw *hw, u8 *addr,
-			     int authorized);
 	int (*hw_scan)(struct ieee80211_hw *hw, u8 *ssid, size_t len);
 	int (*get_stats)(struct ieee80211_hw *hw,
 			 struct ieee80211_low_level_stats *stats);
-	int (*set_privacy_invoked)(struct ieee80211_hw *hw,
-				   int privacy_invoked);
-	int (*get_sequence_counter)(struct ieee80211_hw *hw,
-				    u8* addr, u8 keyidx, u8 txrx,
-				    u32* iv32, u16* iv16);
+	void (*get_tkip_seq)(struct ieee80211_hw *hw, u8 hw_key_idx,
+			     u32 *iv32, u16 *iv16);
 	int (*set_rts_threshold)(struct ieee80211_hw *hw, u32 value);
 	int (*set_frag_threshold)(struct ieee80211_hw *hw, u32 value);
 	int (*set_retry_limit)(struct ieee80211_hw *hw,
 			       u32 short_retry, u32 long_retr);
-	void (*sta_notify)(struct ieee80211_hw *hw, int if_id,
+	void (*sta_notify)(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
 			enum sta_notify_cmd, const u8 *addr);
-	void (*erp_ie_changed)(struct ieee80211_hw *hw, u8 changes,
-			       int cts_protection, int preamble);
 	int (*conf_tx)(struct ieee80211_hw *hw, int queue,
 		       const struct ieee80211_tx_queue_params *params);
 	int (*get_tx_stats)(struct ieee80211_hw *hw,
@@ -1058,6 +1046,10 @@ struct ieee80211_ops {
 			     struct sk_buff *skb,
 			     struct ieee80211_tx_control *control);
 	int (*tx_last_beacon)(struct ieee80211_hw *hw);
+	int (*conf_ht)(struct ieee80211_hw *hw, struct ieee80211_conf *conf);
+	int (*ampdu_action)(struct ieee80211_hw *hw,
+			    enum ieee80211_ampdu_mlme_action action,
+			    const u8 *addr, u16 tid, u16 *ssn);
 };
 
 /**
@@ -1089,6 +1081,7 @@ int ieee80211_register_hw(struct ieee80211_hw *hw);
 extern char *__ieee80211_get_tx_led_name(struct ieee80211_hw *hw);
 extern char *__ieee80211_get_rx_led_name(struct ieee80211_hw *hw);
 extern char *__ieee80211_get_assoc_led_name(struct ieee80211_hw *hw);
+extern char *__ieee80211_get_radio_led_name(struct ieee80211_hw *hw);
 #endif
 /**
  * ieee80211_get_tx_led_name - get name of TX LED
@@ -1128,6 +1121,16 @@ static inline char *ieee80211_get_rx_led_name(struct ieee80211_hw *hw)
 #endif
 }
 
+/**
+ * ieee80211_get_assoc_led_name - get name of association LED
+ *
+ * mac80211 creates a association LED trigger for each wireless hardware
+ * that can be used to drive LEDs if your driver registers a LED device.
+ * This function returns the name (or %NULL if not configured for LEDs)
+ * of the trigger so you can automatically link the LED device.
+ *
+ * @hw: the hardware to get the LED trigger name for
+ */
 static inline char *ieee80211_get_assoc_led_name(struct ieee80211_hw *hw)
 {
 #ifdef CONFIG_MAC80211_LEDS
@@ -1137,10 +1140,24 @@ static inline char *ieee80211_get_assoc_led_name(struct ieee80211_hw *hw)
 #endif
 }
 
-
-/* Register a new hardware PHYMODE capability to the stack. */
-int ieee80211_register_hwmode(struct ieee80211_hw *hw,
-			      struct ieee80211_hw_mode *mode);
+/**
+ * ieee80211_get_radio_led_name - get name of radio LED
+ *
+ * mac80211 creates a radio change LED trigger for each wireless hardware
+ * that can be used to drive LEDs if your driver registers a LED device.
+ * This function returns the name (or %NULL if not configured for LEDs)
+ * of the trigger so you can automatically link the LED device.
+ *
+ * @hw: the hardware to get the LED trigger name for
+ */
+static inline char *ieee80211_get_radio_led_name(struct ieee80211_hw *hw)
+{
+#ifdef CONFIG_MAC80211_LEDS
+	return __ieee80211_get_radio_led_name(hw);
+#else
+	return NULL;
+#endif
+}
 
 /**
  * ieee80211_unregister_hw - Unregister a hardware device
@@ -1226,7 +1243,7 @@ void ieee80211_tx_status_irqsafe(struct ieee80211_hw *hw,
 /**
  * ieee80211_beacon_get - beacon generation function
  * @hw: pointer obtained from ieee80211_alloc_hw().
- * @if_id: interface ID from &struct ieee80211_if_init_conf.
+ * @vif: &struct ieee80211_vif pointer from &struct ieee80211_if_init_conf.
  * @control: will be filled with information needed to send this beacon.
  *
  * If the beacon frames are generated by the host system (i.e., not in
@@ -1237,13 +1254,13 @@ void ieee80211_tx_status_irqsafe(struct ieee80211_hw *hw,
  * is responsible of freeing it.
  */
 struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw,
-				     int if_id,
+				     struct ieee80211_vif *vif,
 				     struct ieee80211_tx_control *control);
 
 /**
  * ieee80211_rts_get - RTS frame generation function
  * @hw: pointer obtained from ieee80211_alloc_hw().
- * @if_id: interface ID from &struct ieee80211_if_init_conf.
+ * @vif: &struct ieee80211_vif pointer from &struct ieee80211_if_init_conf.
  * @frame: pointer to the frame that is going to be protected by the RTS.
  * @frame_len: the frame length (in octets).
  * @frame_txctl: &struct ieee80211_tx_control of the frame.
@@ -1254,7 +1271,7 @@ struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw,
  * the next RTS frame from the 802.11 code. The low-level is responsible
  * for calling this function before and RTS frame is needed.
  */
-void ieee80211_rts_get(struct ieee80211_hw *hw, int if_id,
+void ieee80211_rts_get(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
 		       const void *frame, size_t frame_len,
 		       const struct ieee80211_tx_control *frame_txctl,
 		       struct ieee80211_rts *rts);
@@ -1262,7 +1279,7 @@ void ieee80211_rts_get(struct ieee80211_hw *hw, int if_id,
 /**
  * ieee80211_rts_duration - Get the duration field for an RTS frame
  * @hw: pointer obtained from ieee80211_alloc_hw().
- * @if_id: interface ID from &struct ieee80211_if_init_conf.
+ * @vif: &struct ieee80211_vif pointer from &struct ieee80211_if_init_conf.
  * @frame_len: the length of the frame that is going to be protected by the RTS.
  * @frame_txctl: &struct ieee80211_tx_control of the frame.
  *
@@ -1270,14 +1287,14 @@ void ieee80211_rts_get(struct ieee80211_hw *hw, int if_id,
  * the duration field, the low-level driver uses this function to receive
  * the duration field value in little-endian byteorder.
  */
-__le16 ieee80211_rts_duration(struct ieee80211_hw *hw, int if_id,
-			      size_t frame_len,
+__le16 ieee80211_rts_duration(struct ieee80211_hw *hw,
+			      struct ieee80211_vif *vif, size_t frame_len,
 			      const struct ieee80211_tx_control *frame_txctl);
 
 /**
  * ieee80211_ctstoself_get - CTS-to-self frame generation function
  * @hw: pointer obtained from ieee80211_alloc_hw().
- * @if_id: interface ID from &struct ieee80211_if_init_conf.
+ * @vif: &struct ieee80211_vif pointer from &struct ieee80211_if_init_conf.
  * @frame: pointer to the frame that is going to be protected by the CTS-to-self.
  * @frame_len: the frame length (in octets).
  * @frame_txctl: &struct ieee80211_tx_control of the frame.
@@ -1288,7 +1305,8 @@ __le16 ieee80211_rts_duration(struct ieee80211_hw *hw, int if_id,
  * the next CTS-to-self frame from the 802.11 code. The low-level is responsible
  * for calling this function before and CTS-to-self frame is needed.
  */
-void ieee80211_ctstoself_get(struct ieee80211_hw *hw, int if_id,
+void ieee80211_ctstoself_get(struct ieee80211_hw *hw,
+			     struct ieee80211_vif *vif,
 			     const void *frame, size_t frame_len,
 			     const struct ieee80211_tx_control *frame_txctl,
 			     struct ieee80211_cts *cts);
@@ -1296,7 +1314,7 @@ void ieee80211_ctstoself_get(struct ieee80211_hw *hw, int if_id,
 /**
  * ieee80211_ctstoself_duration - Get the duration field for a CTS-to-self frame
  * @hw: pointer obtained from ieee80211_alloc_hw().
- * @if_id: interface ID from &struct ieee80211_if_init_conf.
+ * @vif: &struct ieee80211_vif pointer from &struct ieee80211_if_init_conf.
  * @frame_len: the length of the frame that is going to be protected by the CTS-to-self.
  * @frame_txctl: &struct ieee80211_tx_control of the frame.
  *
@@ -1304,28 +1322,30 @@ void ieee80211_ctstoself_get(struct ieee80211_hw *hw, int if_id,
  * the duration field, the low-level driver uses this function to receive
  * the duration field value in little-endian byteorder.
  */
-__le16 ieee80211_ctstoself_duration(struct ieee80211_hw *hw, int if_id,
+__le16 ieee80211_ctstoself_duration(struct ieee80211_hw *hw,
+				    struct ieee80211_vif *vif,
 				    size_t frame_len,
 				    const struct ieee80211_tx_control *frame_txctl);
 
 /**
  * ieee80211_generic_frame_duration - Calculate the duration field for a frame
  * @hw: pointer obtained from ieee80211_alloc_hw().
- * @if_id: interface ID from &struct ieee80211_if_init_conf.
+ * @vif: &struct ieee80211_vif pointer from &struct ieee80211_if_init_conf.
  * @frame_len: the length of the frame.
- * @rate: the rate (in 100kbps) at which the frame is going to be transmitted.
+ * @rate: the rate at which the frame is going to be transmitted.
  *
  * Calculate the duration field of some generic frame, given its
  * length and transmission rate (in 100kbps).
  */
-__le16 ieee80211_generic_frame_duration(struct ieee80211_hw *hw, int if_id,
+__le16 ieee80211_generic_frame_duration(struct ieee80211_hw *hw,
+					struct ieee80211_vif *vif,
 					size_t frame_len,
-					int rate);
+					struct ieee80211_rate *rate);
 
 /**
  * ieee80211_get_buffered_bc - accessing buffered broadcast and multicast frames
  * @hw: pointer as obtained from ieee80211_alloc_hw().
- * @if_id: interface ID from &struct ieee80211_if_init_conf.
+ * @vif: &struct ieee80211_vif pointer from &struct ieee80211_if_init_conf.
  * @control: will be filled with information needed to send returned frame.
  *
  * Function for accessing buffered broadcast and multicast frames. If
@@ -1344,7 +1364,7 @@ __le16 ieee80211_generic_frame_duration(struct ieee80211_hw *hw, int if_id,
  * use common code for all beacons.
  */
 struct sk_buff *
-ieee80211_get_buffered_bc(struct ieee80211_hw *hw, int if_id,
+ieee80211_get_buffered_bc(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
 			  struct ieee80211_tx_control *control);
 
 /**
@@ -1422,8 +1442,96 @@ void ieee80211_wake_queues(struct ieee80211_hw *hw);
  */
 void ieee80211_scan_completed(struct ieee80211_hw *hw);
 
-#define MAC_FMT "%02x:%02x:%02x:%02x:%02x:%02x"
-#define MAC_ARG(x) ((u8*)(x))[0], ((u8*)(x))[1], ((u8*)(x))[2], \
-		   ((u8*)(x))[3], ((u8*)(x))[4], ((u8*)(x))[5]
+/**
+ * ieee80211_iterate_active_interfaces - iterate active interfaces
+ *
+ * This function iterates over the interfaces associated with a given
+ * hardware that are currently active and calls the callback for them.
+ *
+ * @hw: the hardware struct of which the interfaces should be iterated over
+ * @iterator: the iterator function to call, cannot sleep
+ * @data: first argument of the iterator function
+ */
+void ieee80211_iterate_active_interfaces(struct ieee80211_hw *hw,
+					 void (*iterator)(void *data, u8 *mac,
+						struct ieee80211_vif *vif),
+					 void *data);
+
+/**
+ * ieee80211_start_tx_ba_session - Start a tx Block Ack session.
+ * @hw: pointer as obtained from ieee80211_alloc_hw().
+ * @ra: receiver address of the BA session recipient
+ * @tid: the TID to BA on.
+ * @return: success if addBA request was sent, failure otherwise
+ *
+ * Although mac80211/low level driver/user space application can estimate
+ * the need to start aggregation on a certain RA/TID, the session level
+ * will be managed by the mac80211.
+ */
+int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid);
+
+/**
+ * ieee80211_start_tx_ba_cb - low level driver ready to aggregate.
+ * @hw: pointer as obtained from ieee80211_alloc_hw().
+ * @ra: receiver address of the BA session recipient.
+ * @tid: the TID to BA on.
+ *
+ * This function must be called by low level driver once it has
+ * finished with preparations for the BA session.
+ */
+void ieee80211_start_tx_ba_cb(struct ieee80211_hw *hw, u8 *ra, u16 tid);
+
+/**
+ * ieee80211_start_tx_ba_cb_irqsafe - low level driver ready to aggregate.
+ * @hw: pointer as obtained from ieee80211_alloc_hw().
+ * @ra: receiver address of the BA session recipient.
+ * @tid: the TID to BA on.
+ *
+ * This function must be called by low level driver once it has
+ * finished with preparations for the BA session.
+ * This version of the function is irq safe.
+ */
+void ieee80211_start_tx_ba_cb_irqsafe(struct ieee80211_hw *hw, const u8 *ra,
+				      u16 tid);
+
+/**
+ * ieee80211_stop_tx_ba_session - Stop a Block Ack session.
+ * @hw: pointer as obtained from ieee80211_alloc_hw().
+ * @ra: receiver address of the BA session recipient
+ * @tid: the TID to stop BA.
+ * @initiator: if indicates initiator DELBA frame will be sent.
+ * @return: error if no sta with matching da found, success otherwise
+ *
+ * Although mac80211/low level driver/user space application can estimate
+ * the need to stop aggregation on a certain RA/TID, the session level
+ * will be managed by the mac80211.
+ */
+int ieee80211_stop_tx_ba_session(struct ieee80211_hw *hw,
+				 u8 *ra, u16 tid,
+				 enum ieee80211_back_parties initiator);
+
+/**
+ * ieee80211_stop_tx_ba_cb - low level driver ready to stop aggregate.
+ * @hw: pointer as obtained from ieee80211_alloc_hw().
+ * @ra: receiver address of the BA session recipient.
+ * @tid: the desired TID to BA on.
+ *
+ * This function must be called by low level driver once it has
+ * finished with preparations for the BA session tear down.
+ */
+void ieee80211_stop_tx_ba_cb(struct ieee80211_hw *hw, u8 *ra, u8 tid);
+
+/**
+ * ieee80211_stop_tx_ba_cb_irqsafe - low level driver ready to stop aggregate.
+ * @hw: pointer as obtained from ieee80211_alloc_hw().
+ * @ra: receiver address of the BA session recipient.
+ * @tid: the desired TID to BA on.
+ *
+ * This function must be called by low level driver once it has
+ * finished with preparations for the BA session tear down.
+ * This version of the function is irq safe.
+ */
+void ieee80211_stop_tx_ba_cb_irqsafe(struct ieee80211_hw *hw, const u8 *ra,
+				     u16 tid);
 
 #endif /* MAC80211_H */
diff --git a/package/mac80211/src/include/net/wireless.h b/package/mac80211/src/include/net/wireless.h
new file mode 100644
index 0000000000..c7f805ee55
--- /dev/null
+++ b/package/mac80211/src/include/net/wireless.h
@@ -0,0 +1,307 @@
+#ifndef __NET_WIRELESS_H
+#define __NET_WIRELESS_H
+
+/*
+ * 802.11 device management
+ *
+ * Copyright 2007	Johannes Berg <johannes@sipsolutions.net>
+ */
+
+#include <linux/netdevice.h>
+#include <linux/debugfs.h>
+#include <linux/list.h>
+#include <net/cfg80211.h>
+
+/**
+ * enum ieee80211_band - supported frequency bands
+ *
+ * The bands are assigned this way because the supported
+ * bitrates differ in these bands.
+ *
+ * @IEEE80211_BAND_2GHZ: 2.4GHz ISM band
+ * @IEEE80211_BAND_5GHZ: around 5GHz band (4.9-5.7)
+ */
+enum ieee80211_band {
+	IEEE80211_BAND_2GHZ,
+	IEEE80211_BAND_5GHZ,
+
+	/* keep last */
+	IEEE80211_NUM_BANDS
+};
+
+/**
+ * enum ieee80211_channel_flags - channel flags
+ *
+ * Channel flags set by the regulatory control code.
+ *
+ * @IEEE80211_CHAN_DISABLED: This channel is disabled.
+ * @IEEE80211_CHAN_PASSIVE_SCAN: Only passive scanning is permitted
+ *	on this channel.
+ * @IEEE80211_CHAN_NO_IBSS: IBSS is not allowed on this channel.
+ * @IEEE80211_CHAN_RADAR: Radar detection is required on this channel.
+ */
+enum ieee80211_channel_flags {
+	IEEE80211_CHAN_DISABLED		= 1<<0,
+	IEEE80211_CHAN_PASSIVE_SCAN	= 1<<1,
+	IEEE80211_CHAN_NO_IBSS		= 1<<2,
+	IEEE80211_CHAN_RADAR		= 1<<3,
+};
+
+/**
+ * struct ieee80211_channel - channel definition
+ *
+ * This structure describes a single channel for use
+ * with cfg80211.
+ *
+ * @center_freq: center frequency in MHz
+ * @hw_value: hardware-specific value for the channel
+ * @flags: channel flags from &enum ieee80211_channel_flags.
+ * @orig_flags: channel flags at registration time, used by regulatory
+ *	code to support devices with additional restrictions
+ * @band: band this channel belongs to.
+ * @max_antenna_gain: maximum antenna gain in dBi
+ * @max_power: maximum transmission power (in dBm)
+ * @orig_mag: internal use
+ * @orig_mpwr: internal use
+ */
+struct ieee80211_channel {
+	enum ieee80211_band band;
+	u16 center_freq;
+	u16 hw_value;
+	u32 flags;
+	int max_antenna_gain;
+	int max_power;
+	u32 orig_flags;
+	int orig_mag, orig_mpwr;
+};
+
+/**
+ * enum ieee80211_rate_flags - rate flags
+ *
+ * Hardware/specification flags for rates. These are structured
+ * in a way that allows using the same bitrate structure for
+ * different bands/PHY modes.
+ *
+ * @IEEE80211_RATE_SHORT_PREAMBLE: Hardware can send with short
+ *	preamble on this bitrate; only relevant in 2.4GHz band and
+ *	with CCK rates.
+ * @IEEE80211_RATE_MANDATORY_A: This bitrate is a mandatory rate
+ *	when used with 802.11a (on the 5 GHz band); filled by the
+ *	core code when registering the wiphy.
+ * @IEEE80211_RATE_MANDATORY_B: This bitrate is a mandatory rate
+ *	when used with 802.11b (on the 2.4 GHz band); filled by the
+ *	core code when registering the wiphy.
+ * @IEEE80211_RATE_MANDATORY_G: This bitrate is a mandatory rate
+ *	when used with 802.11g (on the 2.4 GHz band); filled by the
+ *	core code when registering the wiphy.
+ * @IEEE80211_RATE_ERP_G: This is an ERP rate in 802.11g mode.
+ */
+enum ieee80211_rate_flags {
+	IEEE80211_RATE_SHORT_PREAMBLE	= 1<<0,
+	IEEE80211_RATE_MANDATORY_A	= 1<<1,
+	IEEE80211_RATE_MANDATORY_B	= 1<<2,
+	IEEE80211_RATE_MANDATORY_G	= 1<<3,
+	IEEE80211_RATE_ERP_G		= 1<<4,
+};
+
+/**
+ * struct ieee80211_rate - bitrate definition
+ *
+ * This structure describes a bitrate that an 802.11 PHY can
+ * operate with. The two values @hw_value and @hw_value_short
+ * are only for driver use when pointers to this structure are
+ * passed around.
+ *
+ * @flags: rate-specific flags
+ * @bitrate: bitrate in units of 100 Kbps
+ * @hw_value: driver/hardware value for this rate
+ * @hw_value_short: driver/hardware value for this rate when
+ *	short preamble is used
+ */
+struct ieee80211_rate {
+	u32 flags;
+	u16 bitrate;
+	u16 hw_value, hw_value_short;
+};
+
+/**
+ * struct ieee80211_ht_info - describing STA's HT capabilities
+ *
+ * This structure describes most essential parameters needed
+ * to describe 802.11n HT capabilities for an STA.
+ *
+ * @ht_supported: is HT supported by STA, 0: no, 1: yes
+ * @cap: HT capabilities map as described in 802.11n spec
+ * @ampdu_factor: Maximum A-MPDU length factor
+ * @ampdu_density: Minimum A-MPDU spacing
+ * @supp_mcs_set: Supported MCS set as described in 802.11n spec
+ */
+struct ieee80211_ht_info {
+	u16 cap; /* use IEEE80211_HT_CAP_ */
+	u8 ht_supported;
+	u8 ampdu_factor;
+	u8 ampdu_density;
+	u8 supp_mcs_set[16];
+};
+
+/**
+ * struct ieee80211_supported_band - frequency band definition
+ *
+ * This structure describes a frequency band a wiphy
+ * is able to operate in.
+ *
+ * @channels: Array of channels the hardware can operate in
+ *	in this band.
+ * @band: the band this structure represents
+ * @n_channels: Number of channels in @channels
+ * @bitrates: Array of bitrates the hardware can operate with
+ *	in this band. Must be sorted to give a valid "supported
+ *	rates" IE, i.e. CCK rates first, then OFDM.
+ * @n_bitrates: Number of bitrates in @bitrates
+ */
+struct ieee80211_supported_band {
+	struct ieee80211_channel *channels;
+	struct ieee80211_rate *bitrates;
+	enum ieee80211_band band;
+	int n_channels;
+	int n_bitrates;
+	struct ieee80211_ht_info ht_info;
+};
+
+/**
+ * struct wiphy - wireless hardware description
+ * @idx: the wiphy index assigned to this item
+ * @class_dev: the class device representing /sys/class/ieee80211/<wiphy-name>
+ */
+struct wiphy {
+	/* assign these fields before you register the wiphy */
+
+	/* permanent MAC address */
+	u8 perm_addr[ETH_ALEN];
+
+	/* If multiple wiphys are registered and you're handed e.g.
+	 * a regular netdev with assigned ieee80211_ptr, you won't
+	 * know whether it points to a wiphy your driver has registered
+	 * or not. Assign this to something global to your driver to
+	 * help determine whether you own this wiphy or not. */
+	void *privid;
+
+	struct ieee80211_supported_band *bands[IEEE80211_NUM_BANDS];
+
+	/* fields below are read-only, assigned by cfg80211 */
+
+	/* the item in /sys/class/ieee80211/ points to this,
+	 * you need use set_wiphy_dev() (see below) */
+	struct device dev;
+
+	/* dir in debugfs: ieee80211/<wiphyname> */
+	struct dentry *debugfsdir;
+
+	char priv[0] __attribute__((__aligned__(NETDEV_ALIGN)));
+};
+
+/** struct wireless_dev - wireless per-netdev state
+ *
+ * This structure must be allocated by the driver/stack
+ * that uses the ieee80211_ptr field in struct net_device
+ * (this is intentional so it can be allocated along with
+ * the netdev.)
+ *
+ * @wiphy: pointer to hardware description
+ */
+struct wireless_dev {
+	struct wiphy *wiphy;
+
+	/* private to the generic wireless code */
+	struct list_head list;
+	struct net_device *netdev;
+};
+
+/**
+ * wiphy_priv - return priv from wiphy
+ */
+static inline void *wiphy_priv(struct wiphy *wiphy)
+{
+	BUG_ON(!wiphy);
+	return &wiphy->priv;
+}
+
+/**
+ * set_wiphy_dev - set device pointer for wiphy
+ */
+static inline void set_wiphy_dev(struct wiphy *wiphy, struct device *dev)
+{
+	wiphy->dev.parent = dev;
+}
+
+/**
+ * wiphy_dev - get wiphy dev pointer
+ */
+static inline struct device *wiphy_dev(struct wiphy *wiphy)
+{
+	return wiphy->dev.parent;
+}
+
+/**
+ * wiphy_name - get wiphy name
+ */
+static inline char *wiphy_name(struct wiphy *wiphy)
+{
+	return wiphy->dev.bus_id;
+}
+
+/**
+ * wdev_priv - return wiphy priv from wireless_dev
+ */
+static inline void *wdev_priv(struct wireless_dev *wdev)
+{
+	BUG_ON(!wdev);
+	return wiphy_priv(wdev->wiphy);
+}
+
+/**
+ * wiphy_new - create a new wiphy for use with cfg80211
+ *
+ * create a new wiphy and associate the given operations with it.
+ * @sizeof_priv bytes are allocated for private use.
+ *
+ * the returned pointer must be assigned to each netdev's
+ * ieee80211_ptr for proper operation.
+ */
+struct wiphy *wiphy_new(struct cfg80211_ops *ops, int sizeof_priv);
+
+/**
+ * wiphy_register - register a wiphy with cfg80211
+ *
+ * register the given wiphy
+ *
+ * Returns a non-negative wiphy index or a negative error code.
+ */
+extern int wiphy_register(struct wiphy *wiphy);
+
+/**
+ * wiphy_unregister - deregister a wiphy from cfg80211
+ *
+ * unregister a device with the given priv pointer.
+ * After this call, no more requests can be made with this priv
+ * pointer, but the call may sleep to wait for an outstanding
+ * request that is being handled.
+ */
+extern void wiphy_unregister(struct wiphy *wiphy);
+
+/**
+ * wiphy_free - free wiphy
+ */
+extern void wiphy_free(struct wiphy *wiphy);
+
+/**
+ * ieee80211_channel_to_frequency - convert channel number to frequency
+ */
+extern int ieee80211_channel_to_frequency(int chan);
+
+/**
+ * ieee80211_frequency_to_channel - convert frequency to channel number
+ */
+extern int ieee80211_frequency_to_channel(int freq);
+
+#endif /* __NET_WIRELESS_H */
diff --git a/package/mac80211/src/net/mac80211/Kconfig b/package/mac80211/src/net/mac80211/Kconfig
index 6fffb3845a..45c7c0c387 100644
--- a/package/mac80211/src/net/mac80211/Kconfig
+++ b/package/mac80211/src/net/mac80211/Kconfig
@@ -1,6 +1,5 @@
 config MAC80211
 	tristate "Generic IEEE 802.11 Networking Stack (mac80211)"
-	depends on EXPERIMENTAL
 	select CRYPTO
 	select CRYPTO_ECB
 	select CRYPTO_ARC4
@@ -10,15 +9,84 @@ config MAC80211
 	select CFG80211
 	select NET_SCH_FIFO
 	---help---
-	This option enables the hardware independent IEEE 802.11
-	networking stack.
+	  This option enables the hardware independent IEEE 802.11
+	  networking stack.
+
+menu "Rate control algorithm selection"
+	depends on MAC80211 != n
+
+choice
+	prompt "Default rate control algorithm"
+	default MAC80211_RC_DEFAULT_PID
+	---help---
+	  This option selects the default rate control algorithm
+	  mac80211 will use. Note that this default can still be
+	  overriden through the ieee80211_default_rc_algo module
+	  parameter if different algorithms are available.
+
+config MAC80211_RC_DEFAULT_PID
+	bool "PID controller based rate control algorithm"
+	select MAC80211_RC_PID
+	---help---
+	  Select the PID controller based rate control as the
+	  default rate control algorithm. You should choose
+	  this unless you know what you are doing.
+
+config MAC80211_RC_DEFAULT_SIMPLE
+	bool "Simple rate control algorithm"
+	select MAC80211_RC_SIMPLE
+	---help---
+	  Select the simple rate control as the default rate
+	  control algorithm. Note that this is a non-responsive,
+	  dumb algorithm. You should choose the PID rate control
+	  instead.
+
+config MAC80211_RC_DEFAULT_NONE
+	bool "No default algorithm"
+	depends on EMBEDDED
+	help
+	  Selecting this option will select no default algorithm
+	  and allow you to not build any. Do not choose this
+	  option unless you know your driver comes with another
+	  suitable algorithm.
+endchoice
+
+comment "Selecting 'y' for an algorithm will"
+comment "build the algorithm into mac80211."
+
+config MAC80211_RC_DEFAULT
+	string
+	default "pid" if MAC80211_RC_DEFAULT_PID
+	default "simple" if MAC80211_RC_DEFAULT_SIMPLE
+	default ""
+
+config MAC80211_RC_PID
+	tristate "PID controller based rate control algorithm"
+	---help---
+	  This option enables a TX rate control algorithm for
+	  mac80211 that uses a PID controller to select the TX
+	  rate.
+
+	  Say Y or M unless you're sure you want to use a
+	  different rate control algorithm.
+
+config MAC80211_RC_SIMPLE
+	tristate "Simple rate control algorithm (DEPRECATED)"
+	---help---
+	  This option enables a very simple, non-responsive TX
+	  rate control algorithm. This algorithm is deprecated
+	  and will be removed from the kernel in the near future.
+	  It has been replaced by the PID algorithm.
+
+	  Say N unless you know what you are doing.
+endmenu
 
 config MAC80211_LEDS
 	bool "Enable LED triggers"
 	depends on MAC80211 && LEDS_TRIGGERS
 	---help---
-	This option enables a few LED triggers for different
-	packet receive/transmit events.
+	  This option enables a few LED triggers for different
+	  packet receive/transmit events.
 
 config MAC80211_DEBUGFS
 	bool "Export mac80211 internals in DebugFS"
@@ -29,6 +97,18 @@ config MAC80211_DEBUGFS
 
 	  Say N unless you know you need this.
 
+config MAC80211_DEBUG_PACKET_ALIGNMENT
+	bool "Enable packet alignment debugging"
+	depends on MAC80211
+	help
+	  This option is recommended for driver authors and strongly
+	  discouraged for everybody else, it will trigger a warning
+	  when a driver hands mac80211 a buffer that is aligned in
+	  a way that will cause problems with the IP stack on some
+	  architectures.
+
+	  Say N unless you're writing a mac80211 based driver.
+
 config MAC80211_DEBUG
 	bool "Enable debugging output"
 	depends on MAC80211
@@ -39,6 +119,16 @@ config MAC80211_DEBUG
 	  If you are not trying to debug or develop the ieee80211
 	  subsystem, you most likely want to say N here.
 
+config MAC80211_HT_DEBUG
+	bool "Enable HT debugging output"
+	depends on MAC80211_DEBUG
+	---help---
+	  This option enables 802.11n High Throughput features
+	  debug tracing output.
+
+	  If you are not trying to debug of develop the ieee80211
+	  subsystem, you most likely want to say N here.
+
 config MAC80211_VERBOSE_DEBUG
 	bool "Verbose debugging output"
 	depends on MAC80211_DEBUG
diff --git a/package/mac80211/src/net/mac80211/Makefile b/package/mac80211/src/net/mac80211/Makefile
index 219cd9f934..9d7a19581a 100644
--- a/package/mac80211/src/net/mac80211/Makefile
+++ b/package/mac80211/src/net/mac80211/Makefile
@@ -1,10 +1,15 @@
-obj-$(CONFIG_MAC80211) += mac80211.o rc80211_simple.o
+obj-$(CONFIG_MAC80211) += mac80211.o
 
-mac80211-objs-$(CONFIG_MAC80211_LEDS) += ieee80211_led.o
-mac80211-objs-$(CONFIG_MAC80211_DEBUGFS) += debugfs.o debugfs_sta.o debugfs_netdev.o debugfs_key.o
-mac80211-objs-$(CONFIG_NET_SCHED) += wme.o
+# objects for PID algorithm
+rc80211_pid-y := rc80211_pid_algo.o
+rc80211_pid-$(CONFIG_MAC80211_DEBUGFS) += rc80211_pid_debugfs.o
 
-mac80211-objs := \
+# build helper for PID algorithm
+rc-pid-y := $(rc80211_pid-y)
+rc-pid-m := rc80211_pid.o
+
+# mac80211 objects
+mac80211-y := \
 	ieee80211.o \
 	ieee80211_ioctl.o \
 	sta_info.o \
@@ -14,7 +19,6 @@ mac80211-objs := \
 	ieee80211_iface.o \
 	ieee80211_rate.o \
 	michael.o \
-	regdomain.o \
 	tkip.o \
 	aes_ccm.o \
 	cfg.o \
@@ -22,5 +26,22 @@ mac80211-objs := \
 	tx.o \
 	key.o \
 	util.o \
-	event.o \
-	$(mac80211-objs-y)
+	event.o
+
+mac80211-$(CONFIG_MAC80211_LEDS) += ieee80211_led.o
+mac80211-$(CONFIG_NET_SCHED) += wme.o
+mac80211-$(CONFIG_MAC80211_DEBUGFS) += \
+	debugfs.o \
+	debugfs_sta.o \
+	debugfs_netdev.o \
+	debugfs_key.o
+
+
+# Build rate control algorithm(s)
+CFLAGS_rc80211_simple.o += -DRC80211_SIMPLE_COMPILE
+CFLAGS_rc80211_pid_algo.o += -DRC80211_PID_COMPILE
+mac80211-$(CONFIG_MAC80211_RC_SIMPLE) += rc80211_simple.o
+mac80211-$(CONFIG_MAC80211_RC_PID) += $(rc-pid-$(CONFIG_MAC80211_RC_PID))
+
+# Modular rate algorithms are assigned to mac80211-m - make separate modules
+obj-m += $(mac80211-m)
diff --git a/package/mac80211/src/net/mac80211/aes_ccm.c b/package/mac80211/src/net/mac80211/aes_ccm.c
index e55569bee7..e62fe55944 100644
--- a/package/mac80211/src/net/mac80211/aes_ccm.c
+++ b/package/mac80211/src/net/mac80211/aes_ccm.c
@@ -7,10 +7,10 @@
  * published by the Free Software Foundation.
  */
 
+#include <linux/kernel.h>
 #include <linux/types.h>
 #include <linux/crypto.h>
 #include <linux/err.h>
-#include <asm/scatterlist.h>
 
 #include <net/mac80211.h>
 #include "ieee80211_key.h"
@@ -63,7 +63,7 @@ void ieee80211_aes_ccm_encrypt(struct crypto_cipher *tfm, u8 *scratch,
 	s_0 = scratch + AES_BLOCK_LEN;
 	e = scratch + 2 * AES_BLOCK_LEN;
 
-	num_blocks = (data_len + AES_BLOCK_LEN - 1) / AES_BLOCK_LEN;
+	num_blocks = DIV_ROUND_UP(data_len, AES_BLOCK_LEN);
 	last_len = data_len % AES_BLOCK_LEN;
 	aes_ccm_prepare(tfm, b_0, aad, b, s_0, b);
 
@@ -102,7 +102,7 @@ int ieee80211_aes_ccm_decrypt(struct crypto_cipher *tfm, u8 *scratch,
 	s_0 = scratch + AES_BLOCK_LEN;
 	a = scratch + 2 * AES_BLOCK_LEN;
 
-	num_blocks = (data_len + AES_BLOCK_LEN - 1) / AES_BLOCK_LEN;
+	num_blocks = DIV_ROUND_UP(data_len, AES_BLOCK_LEN);
 	last_len = data_len % AES_BLOCK_LEN;
 	aes_ccm_prepare(tfm, b_0, aad, b, s_0, a);
 
diff --git a/package/mac80211/src/net/mac80211/cfg.c b/package/mac80211/src/net/mac80211/cfg.c
index cd78b3f29c..a083cc7885 100644
--- a/package/mac80211/src/net/mac80211/cfg.c
+++ b/package/mac80211/src/net/mac80211/cfg.c
@@ -1,16 +1,20 @@
 /*
  * mac80211 configuration hooks for cfg80211
  *
- * Copyright 2006	Johannes Berg <johannes@sipsolutions.net>
+ * Copyright 2006, 2007	Johannes Berg <johannes@sipsolutions.net>
  *
  * This file is GPLv2 as found in COPYING.
  */
 
+#include <linux/ieee80211.h>
 #include <linux/nl80211.h>
 #include <linux/rtnetlink.h>
+#include <net/net_namespace.h>
+#include <linux/rcupdate.h>
 #include <net/cfg80211.h>
 #include "ieee80211_i.h"
 #include "cfg.h"
+#include "ieee80211_rate.h"
 
 static enum ieee80211_if_types
 nl80211_type_to_mac80211_type(enum nl80211_iftype type)
@@ -30,10 +34,13 @@ nl80211_type_to_mac80211_type(enum nl80211_iftype type)
 }
 
 static int ieee80211_add_iface(struct wiphy *wiphy, char *name,
-			       enum nl80211_iftype type)
+			       enum nl80211_iftype type, u32 *flags)
 {
 	struct ieee80211_local *local = wiphy_priv(wiphy);
 	enum ieee80211_if_types itype;
+	struct net_device *dev;
+	struct ieee80211_sub_if_data *sdata;
+	int err;
 
 	if (unlikely(local->reg_state != IEEE80211_DEV_REGISTERED))
 		return -ENODEV;
@@ -42,7 +49,13 @@ static int ieee80211_add_iface(struct wiphy *wiphy, char *name,
 	if (itype == IEEE80211_IF_TYPE_INVALID)
 		return -EINVAL;
 
-	return ieee80211_if_add(local->mdev, name, NULL, itype);
+	err = ieee80211_if_add(local->mdev, name, &dev, itype);
+	if (err || itype != IEEE80211_IF_TYPE_MNTR || !flags)
+		return err;
+
+	sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+	sdata->u.mntr_flags = *flags;
+	return 0;
 }
 
 static int ieee80211_del_iface(struct wiphy *wiphy, int ifindex)
@@ -55,7 +68,7 @@ static int ieee80211_del_iface(struct wiphy *wiphy, int ifindex)
 		return -ENODEV;
 
 	/* we're under RTNL */
-	dev = __dev_get_by_index(ifindex);
+	dev = __dev_get_by_index(&init_net, ifindex);
 	if (!dev)
 		return 0;
 
@@ -65,7 +78,7 @@ static int ieee80211_del_iface(struct wiphy *wiphy, int ifindex)
 }
 
 static int ieee80211_change_iface(struct wiphy *wiphy, int ifindex,
-				  enum nl80211_iftype type)
+				  enum nl80211_iftype type, u32 *flags)
 {
 	struct ieee80211_local *local = wiphy_priv(wiphy);
 	struct net_device *dev;
@@ -76,7 +89,7 @@ static int ieee80211_change_iface(struct wiphy *wiphy, int ifindex,
 		return -ENODEV;
 
 	/* we're under RTNL */
-	dev = __dev_get_by_index(ifindex);
+	dev = __dev_get_by_index(&init_net, ifindex);
 	if (!dev)
 		return -ENODEV;
 
@@ -89,12 +102,551 @@ static int ieee80211_change_iface(struct wiphy *wiphy, int ifindex,
 
 	sdata = IEEE80211_DEV_TO_SUB_IF(dev);
 
-        if (sdata->type == IEEE80211_IF_TYPE_VLAN)
+	if (sdata->vif.type == IEEE80211_IF_TYPE_VLAN)
 		return -EOPNOTSUPP;
 
 	ieee80211_if_reinit(dev);
 	ieee80211_if_set_type(dev, itype);
 
+	if (sdata->vif.type != IEEE80211_IF_TYPE_MNTR || !flags)
+		return 0;
+
+	sdata->u.mntr_flags = *flags;
+	return 0;
+}
+
+static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev,
+			     u8 key_idx, u8 *mac_addr,
+			     struct key_params *params)
+{
+	struct ieee80211_sub_if_data *sdata;
+	struct sta_info *sta = NULL;
+	enum ieee80211_key_alg alg;
+	int ret;
+
+	sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+
+	switch (params->cipher) {
+	case WLAN_CIPHER_SUITE_WEP40:
+	case WLAN_CIPHER_SUITE_WEP104:
+		alg = ALG_WEP;
+		break;
+	case WLAN_CIPHER_SUITE_TKIP:
+		alg = ALG_TKIP;
+		break;
+	case WLAN_CIPHER_SUITE_CCMP:
+		alg = ALG_CCMP;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	if (mac_addr) {
+		sta = sta_info_get(sdata->local, mac_addr);
+		if (!sta)
+			return -ENOENT;
+	}
+
+	ret = 0;
+	if (!ieee80211_key_alloc(sdata, sta, alg, key_idx,
+				 params->key_len, params->key))
+		ret = -ENOMEM;
+
+	if (sta)
+		sta_info_put(sta);
+
+	return ret;
+}
+
+static int ieee80211_del_key(struct wiphy *wiphy, struct net_device *dev,
+			     u8 key_idx, u8 *mac_addr)
+{
+	struct ieee80211_sub_if_data *sdata;
+	struct sta_info *sta;
+	int ret;
+
+	sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+
+	if (mac_addr) {
+		sta = sta_info_get(sdata->local, mac_addr);
+		if (!sta)
+			return -ENOENT;
+
+		ret = 0;
+		if (sta->key)
+			ieee80211_key_free(sta->key);
+		else
+			ret = -ENOENT;
+
+		sta_info_put(sta);
+		return ret;
+	}
+
+	if (!sdata->keys[key_idx])
+		return -ENOENT;
+
+	ieee80211_key_free(sdata->keys[key_idx]);
+
+	return 0;
+}
+
+static int ieee80211_get_key(struct wiphy *wiphy, struct net_device *dev,
+			     u8 key_idx, u8 *mac_addr, void *cookie,
+			     void (*callback)(void *cookie,
+					      struct key_params *params))
+{
+	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+	struct sta_info *sta = NULL;
+	u8 seq[6] = {0};
+	struct key_params params;
+	struct ieee80211_key *key;
+	u32 iv32;
+	u16 iv16;
+	int err = -ENOENT;
+
+	if (mac_addr) {
+		sta = sta_info_get(sdata->local, mac_addr);
+		if (!sta)
+			goto out;
+
+		key = sta->key;
+	} else
+		key = sdata->keys[key_idx];
+
+	if (!key)
+		goto out;
+
+	memset(&params, 0, sizeof(params));
+
+	switch (key->conf.alg) {
+	case ALG_TKIP:
+		params.cipher = WLAN_CIPHER_SUITE_TKIP;
+
+		iv32 = key->u.tkip.iv32;
+		iv16 = key->u.tkip.iv16;
+
+		if (key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE &&
+		    sdata->local->ops->get_tkip_seq)
+			sdata->local->ops->get_tkip_seq(
+				local_to_hw(sdata->local),
+				key->conf.hw_key_idx,
+				&iv32, &iv16);
+
+		seq[0] = iv16 & 0xff;
+		seq[1] = (iv16 >> 8) & 0xff;
+		seq[2] = iv32 & 0xff;
+		seq[3] = (iv32 >> 8) & 0xff;
+		seq[4] = (iv32 >> 16) & 0xff;
+		seq[5] = (iv32 >> 24) & 0xff;
+		params.seq = seq;
+		params.seq_len = 6;
+		break;
+	case ALG_CCMP:
+		params.cipher = WLAN_CIPHER_SUITE_CCMP;
+		seq[0] = key->u.ccmp.tx_pn[5];
+		seq[1] = key->u.ccmp.tx_pn[4];
+		seq[2] = key->u.ccmp.tx_pn[3];
+		seq[3] = key->u.ccmp.tx_pn[2];
+		seq[4] = key->u.ccmp.tx_pn[1];
+		seq[5] = key->u.ccmp.tx_pn[0];
+		params.seq = seq;
+		params.seq_len = 6;
+		break;
+	case ALG_WEP:
+		if (key->conf.keylen == 5)
+			params.cipher = WLAN_CIPHER_SUITE_WEP40;
+		else
+			params.cipher = WLAN_CIPHER_SUITE_WEP104;
+		break;
+	}
+
+	params.key = key->conf.key;
+	params.key_len = key->conf.keylen;
+
+	callback(cookie, &params);
+	err = 0;
+
+ out:
+	if (sta)
+		sta_info_put(sta);
+	return err;
+}
+
+static int ieee80211_config_default_key(struct wiphy *wiphy,
+					struct net_device *dev,
+					u8 key_idx)
+{
+	struct ieee80211_sub_if_data *sdata;
+
+	sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+	ieee80211_set_default_key(sdata, key_idx);
+
+	return 0;
+}
+
+static int ieee80211_get_station(struct wiphy *wiphy, struct net_device *dev,
+				 u8 *mac, struct station_stats *stats)
+{
+	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+	struct sta_info *sta;
+
+	sta = sta_info_get(local, mac);
+	if (!sta)
+		return -ENOENT;
+
+	/* XXX: verify sta->dev == dev */
+
+	stats->filled = STATION_STAT_INACTIVE_TIME |
+			STATION_STAT_RX_BYTES |
+			STATION_STAT_TX_BYTES;
+
+	stats->inactive_time = jiffies_to_msecs(jiffies - sta->last_rx);
+	stats->rx_bytes = sta->rx_bytes;
+	stats->tx_bytes = sta->tx_bytes;
+
+	sta_info_put(sta);
+
+	return 0;
+}
+
+/*
+ * This handles both adding a beacon and setting new beacon info
+ */
+static int ieee80211_config_beacon(struct ieee80211_sub_if_data *sdata,
+				   struct beacon_parameters *params)
+{
+	struct beacon_data *new, *old;
+	int new_head_len, new_tail_len;
+	int size;
+	int err = -EINVAL;
+
+	old = sdata->u.ap.beacon;
+
+	/* head must not be zero-length */
+	if (params->head && !params->head_len)
+		return -EINVAL;
+
+	/*
+	 * This is a kludge. beacon interval should really be part
+	 * of the beacon information.
+	 */
+	if (params->interval) {
+		sdata->local->hw.conf.beacon_int = params->interval;
+		if (ieee80211_hw_config(sdata->local))
+			return -EINVAL;
+		/*
+		 * We updated some parameter so if below bails out
+		 * it's not an error.
+		 */
+		err = 0;
+	}
+
+	/* Need to have a beacon head if we don't have one yet */
+	if (!params->head && !old)
+		return err;
+
+	/* sorry, no way to start beaconing without dtim period */
+	if (!params->dtim_period && !old)
+		return err;
+
+	/* new or old head? */
+	if (params->head)
+		new_head_len = params->head_len;
+	else
+		new_head_len = old->head_len;
+
+	/* new or old tail? */
+	if (params->tail || !old)
+		/* params->tail_len will be zero for !params->tail */
+		new_tail_len = params->tail_len;
+	else
+		new_tail_len = old->tail_len;
+
+	size = sizeof(*new) + new_head_len + new_tail_len;
+
+	new = kzalloc(size, GFP_KERNEL);
+	if (!new)
+		return -ENOMEM;
+
+	/* start filling the new info now */
+
+	/* new or old dtim period? */
+	if (params->dtim_period)
+		new->dtim_period = params->dtim_period;
+	else
+		new->dtim_period = old->dtim_period;
+
+	/*
+	 * pointers go into the block we allocated,
+	 * memory is | beacon_data | head | tail |
+	 */
+	new->head = ((u8 *) new) + sizeof(*new);
+	new->tail = new->head + new_head_len;
+	new->head_len = new_head_len;
+	new->tail_len = new_tail_len;
+
+	/* copy in head */
+	if (params->head)
+		memcpy(new->head, params->head, new_head_len);
+	else
+		memcpy(new->head, old->head, new_head_len);
+
+	/* copy in optional tail */
+	if (params->tail)
+		memcpy(new->tail, params->tail, new_tail_len);
+	else
+		if (old)
+			memcpy(new->tail, old->tail, new_tail_len);
+
+	rcu_assign_pointer(sdata->u.ap.beacon, new);
+
+	synchronize_rcu();
+
+	kfree(old);
+
+	return ieee80211_if_config_beacon(sdata->dev);
+}
+
+static int ieee80211_add_beacon(struct wiphy *wiphy, struct net_device *dev,
+				struct beacon_parameters *params)
+{
+	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+	struct beacon_data *old;
+
+	if (sdata->vif.type != IEEE80211_IF_TYPE_AP)
+		return -EINVAL;
+
+	old = sdata->u.ap.beacon;
+
+	if (old)
+		return -EALREADY;
+
+	return ieee80211_config_beacon(sdata, params);
+}
+
+static int ieee80211_set_beacon(struct wiphy *wiphy, struct net_device *dev,
+				struct beacon_parameters *params)
+{
+	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+	struct beacon_data *old;
+
+	if (sdata->vif.type != IEEE80211_IF_TYPE_AP)
+		return -EINVAL;
+
+	old = sdata->u.ap.beacon;
+
+	if (!old)
+		return -ENOENT;
+
+	return ieee80211_config_beacon(sdata, params);
+}
+
+static int ieee80211_del_beacon(struct wiphy *wiphy, struct net_device *dev)
+{
+	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+	struct beacon_data *old;
+
+	if (sdata->vif.type != IEEE80211_IF_TYPE_AP)
+		return -EINVAL;
+
+	old = sdata->u.ap.beacon;
+
+	if (!old)
+		return -ENOENT;
+
+	rcu_assign_pointer(sdata->u.ap.beacon, NULL);
+	synchronize_rcu();
+	kfree(old);
+
+	return ieee80211_if_config_beacon(dev);
+}
+
+/* Layer 2 Update frame (802.2 Type 1 LLC XID Update response) */
+struct iapp_layer2_update {
+	u8 da[ETH_ALEN];	/* broadcast */
+	u8 sa[ETH_ALEN];	/* STA addr */
+	__be16 len;		/* 6 */
+	u8 dsap;		/* 0 */
+	u8 ssap;		/* 0 */
+	u8 control;
+	u8 xid_info[3];
+} __attribute__ ((packed));
+
+static void ieee80211_send_layer2_update(struct sta_info *sta)
+{
+	struct iapp_layer2_update *msg;
+	struct sk_buff *skb;
+
+	/* Send Level 2 Update Frame to update forwarding tables in layer 2
+	 * bridge devices */
+
+	skb = dev_alloc_skb(sizeof(*msg));
+	if (!skb)
+		return;
+	msg = (struct iapp_layer2_update *)skb_put(skb, sizeof(*msg));
+
+	/* 802.2 Type 1 Logical Link Control (LLC) Exchange Identifier (XID)
+	 * Update response frame; IEEE Std 802.2-1998, 5.4.1.2.1 */
+
+	memset(msg->da, 0xff, ETH_ALEN);
+	memcpy(msg->sa, sta->addr, ETH_ALEN);
+	msg->len = htons(6);
+	msg->dsap = 0;
+	msg->ssap = 0x01;	/* NULL LSAP, CR Bit: Response */
+	msg->control = 0xaf;	/* XID response lsb.1111F101.
+				 * F=0 (no poll command; unsolicited frame) */
+	msg->xid_info[0] = 0x81;	/* XID format identifier */
+	msg->xid_info[1] = 1;	/* LLC types/classes: Type 1 LLC */
+	msg->xid_info[2] = 0;	/* XID sender's receive window size (RW) */
+
+	skb->dev = sta->dev;
+	skb->protocol = eth_type_trans(skb, sta->dev);
+	memset(skb->cb, 0, sizeof(skb->cb));
+	netif_rx(skb);
+}
+
+static void sta_apply_parameters(struct ieee80211_local *local,
+				 struct sta_info *sta,
+				 struct station_parameters *params)
+{
+	u32 rates;
+	int i, j;
+	struct ieee80211_supported_band *sband;
+
+	if (params->station_flags & STATION_FLAG_CHANGED) {
+		sta->flags &= ~WLAN_STA_AUTHORIZED;
+		if (params->station_flags & STATION_FLAG_AUTHORIZED)
+			sta->flags |= WLAN_STA_AUTHORIZED;
+
+		sta->flags &= ~WLAN_STA_SHORT_PREAMBLE;
+		if (params->station_flags & STATION_FLAG_SHORT_PREAMBLE)
+			sta->flags |= WLAN_STA_SHORT_PREAMBLE;
+
+		sta->flags &= ~WLAN_STA_WME;
+		if (params->station_flags & STATION_FLAG_WME)
+			sta->flags |= WLAN_STA_WME;
+	}
+
+	if (params->aid) {
+		sta->aid = params->aid;
+		if (sta->aid > IEEE80211_MAX_AID)
+			sta->aid = 0; /* XXX: should this be an error? */
+	}
+
+	if (params->listen_interval >= 0)
+		sta->listen_interval = params->listen_interval;
+
+	if (params->supported_rates) {
+		rates = 0;
+		sband = local->hw.wiphy->bands[local->oper_channel->band];
+
+		for (i = 0; i < params->supported_rates_len; i++) {
+			int rate = (params->supported_rates[i] & 0x7f) * 5;
+			for (j = 0; j < sband->n_bitrates; j++) {
+				if (sband->bitrates[j].bitrate == rate)
+					rates |= BIT(j);
+			}
+		}
+		sta->supp_rates[local->oper_channel->band] = rates;
+	}
+}
+
+static int ieee80211_add_station(struct wiphy *wiphy, struct net_device *dev,
+				 u8 *mac, struct station_parameters *params)
+{
+	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+	struct sta_info *sta;
+	struct ieee80211_sub_if_data *sdata;
+
+	/* Prevent a race with changing the rate control algorithm */
+	if (!netif_running(dev))
+		return -ENETDOWN;
+
+	/* XXX: get sta belonging to dev */
+	sta = sta_info_get(local, mac);
+	if (sta) {
+		sta_info_put(sta);
+		return -EEXIST;
+	}
+
+	if (params->vlan) {
+		sdata = IEEE80211_DEV_TO_SUB_IF(params->vlan);
+
+		if (sdata->vif.type != IEEE80211_IF_TYPE_VLAN ||
+		    sdata->vif.type != IEEE80211_IF_TYPE_AP)
+			return -EINVAL;
+	} else
+		sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+
+	sta = sta_info_add(local, dev, mac, GFP_KERNEL);
+	if (!sta)
+		return -ENOMEM;
+
+	sta->dev = sdata->dev;
+	if (sdata->vif.type == IEEE80211_IF_TYPE_VLAN ||
+	    sdata->vif.type == IEEE80211_IF_TYPE_AP)
+		ieee80211_send_layer2_update(sta);
+
+	sta->flags = WLAN_STA_AUTH | WLAN_STA_ASSOC;
+
+	sta_apply_parameters(local, sta, params);
+
+	rate_control_rate_init(sta, local);
+
+	sta_info_put(sta);
+
+	return 0;
+}
+
+static int ieee80211_del_station(struct wiphy *wiphy, struct net_device *dev,
+				 u8 *mac)
+{
+	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+	struct sta_info *sta;
+
+	if (mac) {
+		/* XXX: get sta belonging to dev */
+		sta = sta_info_get(local, mac);
+		if (!sta)
+			return -ENOENT;
+
+		sta_info_free(sta);
+		sta_info_put(sta);
+	} else
+		sta_info_flush(local, dev);
+
+	return 0;
+}
+
+static int ieee80211_change_station(struct wiphy *wiphy,
+				    struct net_device *dev,
+				    u8 *mac,
+				    struct station_parameters *params)
+{
+	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+	struct sta_info *sta;
+	struct ieee80211_sub_if_data *vlansdata;
+
+	/* XXX: get sta belonging to dev */
+	sta = sta_info_get(local, mac);
+	if (!sta)
+		return -ENOENT;
+
+	if (params->vlan && params->vlan != sta->dev) {
+		vlansdata = IEEE80211_DEV_TO_SUB_IF(params->vlan);
+
+		if (vlansdata->vif.type != IEEE80211_IF_TYPE_VLAN ||
+		    vlansdata->vif.type != IEEE80211_IF_TYPE_AP)
+			return -EINVAL;
+
+		sta->dev = params->vlan;
+		ieee80211_send_layer2_update(sta);
+	}
+
+	sta_apply_parameters(local, sta, params);
+
+	sta_info_put(sta);
+
 	return 0;
 }
 
@@ -102,4 +654,15 @@ struct cfg80211_ops mac80211_config_ops = {
 	.add_virtual_intf = ieee80211_add_iface,
 	.del_virtual_intf = ieee80211_del_iface,
 	.change_virtual_intf = ieee80211_change_iface,
+	.add_key = ieee80211_add_key,
+	.del_key = ieee80211_del_key,
+	.get_key = ieee80211_get_key,
+	.set_default_key = ieee80211_config_default_key,
+	.add_beacon = ieee80211_add_beacon,
+	.set_beacon = ieee80211_set_beacon,
+	.del_beacon = ieee80211_del_beacon,
+	.add_station = ieee80211_add_station,
+	.del_station = ieee80211_del_station,
+	.change_station = ieee80211_change_station,
+	.get_station = ieee80211_get_station,
 };
diff --git a/package/mac80211/src/net/mac80211/debugfs.c b/package/mac80211/src/net/mac80211/debugfs.c
index 60514b2c97..4736c64937 100644
--- a/package/mac80211/src/net/mac80211/debugfs.c
+++ b/package/mac80211/src/net/mac80211/debugfs.c
@@ -19,41 +19,6 @@ int mac80211_open_file_generic(struct inode *inode, struct file *file)
 	return 0;
 }
 
-static const char *ieee80211_mode_str(int mode)
-{
-	switch (mode) {
-	case MODE_IEEE80211A:
-		return "IEEE 802.11a";
-	case MODE_IEEE80211B:
-		return "IEEE 802.11b";
-	case MODE_IEEE80211G:
-		return "IEEE 802.11g";
-	default:
-		return "UNKNOWN";
-	}
-}
-
-static ssize_t modes_read(struct file *file, char __user *userbuf,
-			  size_t count, loff_t *ppos)
-{
-	struct ieee80211_local *local = file->private_data;
-	struct ieee80211_hw_mode *mode;
-	char buf[150], *p = buf;
-
-	/* FIXME: locking! */
-	list_for_each_entry(mode, &local->modes_list, list) {
-		p += scnprintf(p, sizeof(buf)+buf-p,
-			       "%s\n", ieee80211_mode_str(mode->mode));
-	}
-
-	return simple_read_from_buffer(userbuf, count, ppos, buf, p-buf);
-}
-
-static const struct file_operations modes_ops = {
-	.read = modes_read,
-	.open = mac80211_open_file_generic,
-};
-
 #define DEBUGFS_READONLY_FILE(name, buflen, fmt, value...)		\
 static ssize_t name## _read(struct file *file, char __user *userbuf,	\
 			    size_t count, loff_t *ppos)			\
@@ -80,10 +45,8 @@ static const struct file_operations name## _ops = {			\
 	local->debugfs.name = NULL;
 
 
-DEBUGFS_READONLY_FILE(channel, 20, "%d",
-		      local->hw.conf.channel);
 DEBUGFS_READONLY_FILE(frequency, 20, "%d",
-		      local->hw.conf.freq);
+		      local->hw.conf.channel->center_freq);
 DEBUGFS_READONLY_FILE(antenna_sel_tx, 20, "%d",
 		      local->hw.conf.antenna_sel_tx);
 DEBUGFS_READONLY_FILE(antenna_sel_rx, 20, "%d",
@@ -100,8 +63,6 @@ DEBUGFS_READONLY_FILE(long_retry_limit, 20, "%d",
 		      local->long_retry_limit);
 DEBUGFS_READONLY_FILE(total_ps_buffered, 20, "%d",
 		      local->total_ps_buffered);
-DEBUGFS_READONLY_FILE(mode, 20, "%s",
-		      ieee80211_mode_str(local->hw.conf.phymode));
 DEBUGFS_READONLY_FILE(wep_iv, 20, "%#06x",
 		      local->wep_iv & 0xffffff);
 DEBUGFS_READONLY_FILE(rate_ctrl_alg, 100, "%s",
@@ -294,7 +255,6 @@ void debugfs_hw_add(struct ieee80211_local *local)
 	local->debugfs.stations = debugfs_create_dir("stations", phyd);
 	local->debugfs.keys = debugfs_create_dir("keys", phyd);
 
-	DEBUGFS_ADD(channel);
 	DEBUGFS_ADD(frequency);
 	DEBUGFS_ADD(antenna_sel_tx);
 	DEBUGFS_ADD(antenna_sel_rx);
@@ -304,9 +264,7 @@ void debugfs_hw_add(struct ieee80211_local *local)
 	DEBUGFS_ADD(short_retry_limit);
 	DEBUGFS_ADD(long_retry_limit);
 	DEBUGFS_ADD(total_ps_buffered);
-	DEBUGFS_ADD(mode);
 	DEBUGFS_ADD(wep_iv);
-	DEBUGFS_ADD(modes);
 
 	statsd = debugfs_create_dir("statistics", phyd);
 	local->debugfs.statistics = statsd;
@@ -356,7 +314,6 @@ void debugfs_hw_add(struct ieee80211_local *local)
 
 void debugfs_hw_del(struct ieee80211_local *local)
 {
-	DEBUGFS_DEL(channel);
 	DEBUGFS_DEL(frequency);
 	DEBUGFS_DEL(antenna_sel_tx);
 	DEBUGFS_DEL(antenna_sel_rx);
@@ -366,9 +323,7 @@ void debugfs_hw_del(struct ieee80211_local *local)
 	DEBUGFS_DEL(short_retry_limit);
 	DEBUGFS_DEL(long_retry_limit);
 	DEBUGFS_DEL(total_ps_buffered);
-	DEBUGFS_DEL(mode);
 	DEBUGFS_DEL(wep_iv);
-	DEBUGFS_DEL(modes);
 
 	DEBUGFS_STATS_DEL(transmitted_fragment_count);
 	DEBUGFS_STATS_DEL(multicast_transmitted_frame_count);
diff --git a/package/mac80211/src/net/mac80211/debugfs_key.c b/package/mac80211/src/net/mac80211/debugfs_key.c
index 8e4a1bcd16..c881524c87 100644
--- a/package/mac80211/src/net/mac80211/debugfs_key.c
+++ b/package/mac80211/src/net/mac80211/debugfs_key.c
@@ -262,11 +262,12 @@ void ieee80211_debugfs_key_sta_link(struct ieee80211_key *key,
 				    struct sta_info *sta)
 {
 	char buf[50];
+	DECLARE_MAC_BUF(mac);
 
 	if (!key->debugfs.dir)
 		return;
 
-	sprintf(buf, "../../stations/" MAC_FMT, MAC_ARG(sta->addr));
+	sprintf(buf, "../../stations/%s", print_mac(mac, sta->addr));
 	key->debugfs.stalink =
 		debugfs_create_symlink("station", key->debugfs.dir, buf);
 }
diff --git a/package/mac80211/src/net/mac80211/debugfs_netdev.c b/package/mac80211/src/net/mac80211/debugfs_netdev.c
index 2b5e7615e5..29f7b98ba1 100644
--- a/package/mac80211/src/net/mac80211/debugfs_netdev.c
+++ b/package/mac80211/src/net/mac80211/debugfs_netdev.c
@@ -66,7 +66,8 @@ static ssize_t ieee80211_if_fmt_##name(					\
 	const struct ieee80211_sub_if_data *sdata, char *buf,		\
 	int buflen)							\
 {									\
-	return scnprintf(buf, buflen, MAC_FMT "\n", MAC_ARG(sdata->field));\
+	DECLARE_MAC_BUF(mac);						\
+	return scnprintf(buf, buflen, "%s\n", print_mac(mac, sdata->field));\
 }
 
 #define __IEEE80211_IF_FILE(name)					\
@@ -90,8 +91,6 @@ static const struct file_operations name##_ops = {			\
 /* common attributes */
 IEEE80211_IF_FILE(channel_use, channel_use, DEC);
 IEEE80211_IF_FILE(drop_unencrypted, drop_unencrypted, DEC);
-IEEE80211_IF_FILE(eapol, eapol, DEC);
-IEEE80211_IF_FILE(ieee8021_x, ieee802_1x, DEC);
 
 /* STA/IBSS attributes */
 IEEE80211_IF_FILE(state, u.sta.state, DEC);
@@ -118,13 +117,12 @@ static ssize_t ieee80211_if_fmt_flags(
 		 sdata->u.sta.flags & IEEE80211_STA_AUTHENTICATED ? "AUTH\n" : "",
 		 sdata->u.sta.flags & IEEE80211_STA_ASSOCIATED ? "ASSOC\n" : "",
 		 sdata->u.sta.flags & IEEE80211_STA_PROBEREQ_POLL ? "PROBEREQ POLL\n" : "",
-		 sdata->flags & IEEE80211_SDATA_USE_PROTECTION ? "CTS prot\n" : "");
+		 sdata->bss_conf.use_cts_prot ? "CTS prot\n" : "");
 }
 __IEEE80211_IF_FILE(flags);
 
 /* AP attributes */
 IEEE80211_IF_FILE(num_sta_ps, u.ap.num_sta_ps, ATOMIC);
-IEEE80211_IF_FILE(dtim_period, u.ap.dtim_period, DEC);
 IEEE80211_IF_FILE(dtim_count, u.ap.dtim_count, DEC);
 IEEE80211_IF_FILE(num_beacons, u.ap.num_beacons, DEC);
 IEEE80211_IF_FILE(force_unicast_rateidx, u.ap.force_unicast_rateidx, DEC);
@@ -138,26 +136,6 @@ static ssize_t ieee80211_if_fmt_num_buffered_multicast(
 }
 __IEEE80211_IF_FILE(num_buffered_multicast);
 
-static ssize_t ieee80211_if_fmt_beacon_head_len(
-	const struct ieee80211_sub_if_data *sdata, char *buf, int buflen)
-{
-	if (sdata->u.ap.beacon_head)
-		return scnprintf(buf, buflen, "%d\n",
-				 sdata->u.ap.beacon_head_len);
-	return scnprintf(buf, buflen, "\n");
-}
-__IEEE80211_IF_FILE(beacon_head_len);
-
-static ssize_t ieee80211_if_fmt_beacon_tail_len(
-	const struct ieee80211_sub_if_data *sdata, char *buf, int buflen)
-{
-	if (sdata->u.ap.beacon_tail)
-		return scnprintf(buf, buflen, "%d\n",
-				 sdata->u.ap.beacon_tail_len);
-	return scnprintf(buf, buflen, "\n");
-}
-__IEEE80211_IF_FILE(beacon_tail_len);
-
 /* WDS attributes */
 IEEE80211_IF_FILE(peer, u.wds.remote_addr, MAC);
 
@@ -169,8 +147,6 @@ static void add_sta_files(struct ieee80211_sub_if_data *sdata)
 {
 	DEBUGFS_ADD(channel_use, sta);
 	DEBUGFS_ADD(drop_unencrypted, sta);
-	DEBUGFS_ADD(eapol, sta);
-	DEBUGFS_ADD(ieee8021_x, sta);
 	DEBUGFS_ADD(state, sta);
 	DEBUGFS_ADD(bssid, sta);
 	DEBUGFS_ADD(prev_bssid, sta);
@@ -191,25 +167,18 @@ static void add_ap_files(struct ieee80211_sub_if_data *sdata)
 {
 	DEBUGFS_ADD(channel_use, ap);
 	DEBUGFS_ADD(drop_unencrypted, ap);
-	DEBUGFS_ADD(eapol, ap);
-	DEBUGFS_ADD(ieee8021_x, ap);
 	DEBUGFS_ADD(num_sta_ps, ap);
-	DEBUGFS_ADD(dtim_period, ap);
 	DEBUGFS_ADD(dtim_count, ap);
 	DEBUGFS_ADD(num_beacons, ap);
 	DEBUGFS_ADD(force_unicast_rateidx, ap);
 	DEBUGFS_ADD(max_ratectrl_rateidx, ap);
 	DEBUGFS_ADD(num_buffered_multicast, ap);
-	DEBUGFS_ADD(beacon_head_len, ap);
-	DEBUGFS_ADD(beacon_tail_len, ap);
 }
 
 static void add_wds_files(struct ieee80211_sub_if_data *sdata)
 {
 	DEBUGFS_ADD(channel_use, wds);
 	DEBUGFS_ADD(drop_unencrypted, wds);
-	DEBUGFS_ADD(eapol, wds);
-	DEBUGFS_ADD(ieee8021_x, wds);
 	DEBUGFS_ADD(peer, wds);
 }
 
@@ -217,8 +186,6 @@ static void add_vlan_files(struct ieee80211_sub_if_data *sdata)
 {
 	DEBUGFS_ADD(channel_use, vlan);
 	DEBUGFS_ADD(drop_unencrypted, vlan);
-	DEBUGFS_ADD(eapol, vlan);
-	DEBUGFS_ADD(ieee8021_x, vlan);
 }
 
 static void add_monitor_files(struct ieee80211_sub_if_data *sdata)
@@ -230,7 +197,7 @@ static void add_files(struct ieee80211_sub_if_data *sdata)
 	if (!sdata->debugfsdir)
 		return;
 
-	switch (sdata->type) {
+	switch (sdata->vif.type) {
 	case IEEE80211_IF_TYPE_STA:
 	case IEEE80211_IF_TYPE_IBSS:
 		add_sta_files(sdata);
@@ -262,8 +229,6 @@ static void del_sta_files(struct ieee80211_sub_if_data *sdata)
 {
 	DEBUGFS_DEL(channel_use, sta);
 	DEBUGFS_DEL(drop_unencrypted, sta);
-	DEBUGFS_DEL(eapol, sta);
-	DEBUGFS_DEL(ieee8021_x, sta);
 	DEBUGFS_DEL(state, sta);
 	DEBUGFS_DEL(bssid, sta);
 	DEBUGFS_DEL(prev_bssid, sta);
@@ -284,25 +249,18 @@ static void del_ap_files(struct ieee80211_sub_if_data *sdata)
 {
 	DEBUGFS_DEL(channel_use, ap);
 	DEBUGFS_DEL(drop_unencrypted, ap);
-	DEBUGFS_DEL(eapol, ap);
-	DEBUGFS_DEL(ieee8021_x, ap);
 	DEBUGFS_DEL(num_sta_ps, ap);
-	DEBUGFS_DEL(dtim_period, ap);
 	DEBUGFS_DEL(dtim_count, ap);
 	DEBUGFS_DEL(num_beacons, ap);
 	DEBUGFS_DEL(force_unicast_rateidx, ap);
 	DEBUGFS_DEL(max_ratectrl_rateidx, ap);
 	DEBUGFS_DEL(num_buffered_multicast, ap);
-	DEBUGFS_DEL(beacon_head_len, ap);
-	DEBUGFS_DEL(beacon_tail_len, ap);
 }
 
 static void del_wds_files(struct ieee80211_sub_if_data *sdata)
 {
 	DEBUGFS_DEL(channel_use, wds);
 	DEBUGFS_DEL(drop_unencrypted, wds);
-	DEBUGFS_DEL(eapol, wds);
-	DEBUGFS_DEL(ieee8021_x, wds);
 	DEBUGFS_DEL(peer, wds);
 }
 
@@ -310,8 +268,6 @@ static void del_vlan_files(struct ieee80211_sub_if_data *sdata)
 {
 	DEBUGFS_DEL(channel_use, vlan);
 	DEBUGFS_DEL(drop_unencrypted, vlan);
-	DEBUGFS_DEL(eapol, vlan);
-	DEBUGFS_DEL(ieee8021_x, vlan);
 }
 
 static void del_monitor_files(struct ieee80211_sub_if_data *sdata)
@@ -361,7 +317,7 @@ void ieee80211_debugfs_add_netdev(struct ieee80211_sub_if_data *sdata)
 
 void ieee80211_debugfs_remove_netdev(struct ieee80211_sub_if_data *sdata)
 {
-	del_files(sdata, sdata->type);
+	del_files(sdata, sdata->vif.type);
 	debugfs_remove(sdata->debugfsdir);
 	sdata->debugfsdir = NULL;
 }
diff --git a/package/mac80211/src/net/mac80211/debugfs_sta.c b/package/mac80211/src/net/mac80211/debugfs_sta.c
index 4ea0ea7ea0..ac61353ae7 100644
--- a/package/mac80211/src/net/mac80211/debugfs_sta.c
+++ b/package/mac80211/src/net/mac80211/debugfs_sta.c
@@ -33,25 +33,16 @@ static ssize_t sta_ ##name## _read(struct file *file,			\
 #define STA_READ_LU(name, field) STA_READ(name, 20, field, "%lu\n")
 #define STA_READ_S(name, field) STA_READ(name, 20, field, "%s\n")
 
-#define STA_READ_RATE(name, field)					\
-static ssize_t sta_##name##_read(struct file *file,			\
-				 char __user *userbuf,			\
-				 size_t count, loff_t *ppos)		\
-{									\
-	struct sta_info *sta = file->private_data;			\
-	struct ieee80211_local *local = wdev_priv(sta->dev->ieee80211_ptr);\
-	struct ieee80211_hw_mode *mode = local->oper_hw_mode;		\
-	char buf[20];							\
-	int res = scnprintf(buf, sizeof(buf), "%d\n",			\
-			    (sta->field >= 0 &&				\
-			    sta->field < mode->num_rates) ?		\
-			    mode->rates[sta->field].rate : -1);		\
-	return simple_read_from_buffer(userbuf, count, ppos, buf, res);	\
+#define STA_OPS(name)							\
+static const struct file_operations sta_ ##name## _ops = {		\
+	.read = sta_##name##_read,					\
+	.open = mac80211_open_file_generic,				\
 }
 
-#define STA_OPS(name)							\
+#define STA_OPS_WR(name)						\
 static const struct file_operations sta_ ##name## _ops = {		\
 	.read = sta_##name##_read,					\
+	.write = sta_##name##_write,					\
 	.open = mac80211_open_file_generic,				\
 }
 
@@ -70,8 +61,6 @@ STA_FILE(rx_fragments, rx_fragments, LU);
 STA_FILE(rx_dropped, rx_dropped, LU);
 STA_FILE(tx_fragments, tx_fragments, LU);
 STA_FILE(tx_filtered, tx_filtered_count, LU);
-STA_FILE(txrate, txrate, RATE);
-STA_FILE(last_txrate, last_txrate, RATE);
 STA_FILE(tx_retry_failed, tx_retry_failed, LU);
 STA_FILE(tx_retry_count, tx_retry_count, LU);
 STA_FILE(last_rssi, last_rssi, D);
@@ -85,12 +74,11 @@ static ssize_t sta_flags_read(struct file *file, char __user *userbuf,
 {
 	char buf[100];
 	struct sta_info *sta = file->private_data;
-	int res = scnprintf(buf, sizeof(buf), "%s%s%s%s%s%s%s%s%s",
+	int res = scnprintf(buf, sizeof(buf), "%s%s%s%s%s%s%s%s",
 		sta->flags & WLAN_STA_AUTH ? "AUTH\n" : "",
 		sta->flags & WLAN_STA_ASSOC ? "ASSOC\n" : "",
 		sta->flags & WLAN_STA_PS ? "PS\n" : "",
 		sta->flags & WLAN_STA_TIM ? "TIM\n" : "",
-		sta->flags & WLAN_STA_PERM ? "PERM\n" : "",
 		sta->flags & WLAN_STA_AUTHORIZED ? "AUTHORIZED\n" : "",
 		sta->flags & WLAN_STA_SHORT_PREAMBLE ? "SHORT PREAMBLE\n" : "",
 		sta->flags & WLAN_STA_WME ? "WME\n" : "",
@@ -191,6 +179,113 @@ static ssize_t sta_wme_tx_queue_read(struct file *file, char __user *userbuf,
 STA_OPS(wme_tx_queue);
 #endif
 
+static ssize_t sta_agg_status_read(struct file *file, char __user *userbuf,
+					size_t count, loff_t *ppos)
+{
+	char buf[768], *p = buf;
+	int i;
+	struct sta_info *sta = file->private_data;
+	p += scnprintf(p, sizeof(buf)+buf-p, "Agg state for STA is:\n");
+	p += scnprintf(p, sizeof(buf)+buf-p, " STA next dialog_token is %d \n "
+			"TIDs info is: \n TID :",
+			(sta->ampdu_mlme.dialog_token_allocator + 1));
+	for (i = 0; i < STA_TID_NUM; i++)
+		p += scnprintf(p, sizeof(buf)+buf-p, "%5d", i);
+
+	p += scnprintf(p, sizeof(buf)+buf-p, "\n RX  :");
+	for (i = 0; i < STA_TID_NUM; i++)
+		p += scnprintf(p, sizeof(buf)+buf-p, "%5d",
+	sta->ampdu_mlme.tid_rx[i].state);
+
+	p += scnprintf(p, sizeof(buf)+buf-p, "\n DTKN:");
+	for (i = 0; i < STA_TID_NUM; i++)
+		p += scnprintf(p, sizeof(buf)+buf-p, "%5d",
+			sta->ampdu_mlme.tid_rx[i].dialog_token);
+
+	p += scnprintf(p, sizeof(buf)+buf-p, "\n TX  :");
+	for (i = 0; i < STA_TID_NUM; i++)
+		p += scnprintf(p, sizeof(buf)+buf-p, "%5d",
+			sta->ampdu_mlme.tid_tx[i].state);
+
+	p += scnprintf(p, sizeof(buf)+buf-p, "\n DTKN:");
+	for (i = 0; i < STA_TID_NUM; i++)
+		p += scnprintf(p, sizeof(buf)+buf-p, "%5d",
+			sta->ampdu_mlme.tid_tx[i].dialog_token);
+
+	p += scnprintf(p, sizeof(buf)+buf-p, "\n SSN :");
+	for (i = 0; i < STA_TID_NUM; i++)
+		p += scnprintf(p, sizeof(buf)+buf-p, "%5d",
+			sta->ampdu_mlme.tid_tx[i].ssn);
+
+	p += scnprintf(p, sizeof(buf)+buf-p, "\n");
+
+	return simple_read_from_buffer(userbuf, count, ppos, buf, p - buf);
+}
+
+static ssize_t sta_agg_status_write(struct file *file,
+		const char __user *user_buf, size_t count, loff_t *ppos)
+{
+	struct sta_info *sta = file->private_data;
+	struct net_device *dev = sta->dev;
+	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+	struct ieee80211_hw *hw = &local->hw;
+	u8 *da = sta->addr;
+	static int tid_static_tx[16] = {0, 0, 0, 0, 0, 0, 0, 0,
+					0, 0, 0, 0, 0, 0, 0, 0};
+	static int tid_static_rx[16] = {1, 1, 1, 1, 1, 1, 1, 1,
+					1, 1, 1, 1, 1, 1, 1, 1};
+	char *endp;
+	char buf[32];
+	int buf_size, rs;
+	unsigned int tid_num;
+	char state[4];
+
+	memset(buf, 0x00, sizeof(buf));
+	buf_size = min(count, (sizeof(buf)-1));
+	if (copy_from_user(buf, user_buf, buf_size))
+		return -EFAULT;
+
+	tid_num = simple_strtoul(buf, &endp, 0);
+	if (endp == buf)
+		return -EINVAL;
+
+	if ((tid_num >= 100) && (tid_num <= 115)) {
+		/* toggle Rx aggregation command */
+		tid_num = tid_num - 100;
+		if (tid_static_rx[tid_num] == 1) {
+			strcpy(state, "off ");
+			ieee80211_sta_stop_rx_ba_session(dev, da, tid_num, 0,
+					WLAN_REASON_QSTA_REQUIRE_SETUP);
+			sta->ampdu_mlme.tid_rx[tid_num].buf_size = 0xFF;
+			tid_static_rx[tid_num] = 0;
+		} else {
+			strcpy(state, "on ");
+			sta->ampdu_mlme.tid_rx[tid_num].buf_size = 0x00;
+			tid_static_rx[tid_num] = 1;
+		}
+		printk(KERN_DEBUG "debugfs - try switching tid %u %s\n",
+				tid_num, state);
+	} else if ((tid_num >= 0) && (tid_num <= 15)) {
+		/* toggle Tx aggregation command */
+		if (tid_static_tx[tid_num] == 0) {
+			strcpy(state, "on ");
+			rs =  ieee80211_start_tx_ba_session(hw, da, tid_num);
+			if (rs == 0)
+				tid_static_tx[tid_num] = 1;
+		} else {
+			strcpy(state, "off");
+			rs =  ieee80211_stop_tx_ba_session(hw, da, tid_num, 1);
+			if (rs == 0)
+				tid_static_tx[tid_num] = 0;
+		}
+		printk(KERN_DEBUG "debugfs - switching tid %u %s, return=%d\n",
+				tid_num, state, rs);
+	}
+
+	return count;
+}
+STA_OPS_WR(agg_status);
+
 #define DEBUGFS_ADD(name) \
 	sta->debugfs.name = debugfs_create_file(#name, 0444, \
 		sta->debugfs.dir, sta, &sta_ ##name## _ops);
@@ -202,15 +297,15 @@ STA_OPS(wme_tx_queue);
 
 void ieee80211_sta_debugfs_add(struct sta_info *sta)
 {
-	char buf[3*6];
 	struct dentry *stations_dir = sta->local->debugfs.stations;
+	DECLARE_MAC_BUF(mac);
 
 	if (!stations_dir)
 		return;
 
-	sprintf(buf, MAC_FMT, MAC_ARG(sta->addr));
+	print_mac(mac, sta->addr);
 
-	sta->debugfs.dir = debugfs_create_dir(buf, stations_dir);
+	sta->debugfs.dir = debugfs_create_dir(mac, stations_dir);
 	if (!sta->debugfs.dir)
 		return;
 
@@ -224,6 +319,7 @@ void ieee80211_sta_debugfs_add(struct sta_info *sta)
 	DEBUGFS_ADD(wme_rx_queue);
 	DEBUGFS_ADD(wme_tx_queue);
 #endif
+	DEBUGFS_ADD(agg_status);
 }
 
 void ieee80211_sta_debugfs_remove(struct sta_info *sta)
@@ -238,6 +334,7 @@ void ieee80211_sta_debugfs_remove(struct sta_info *sta)
 	DEBUGFS_DEL(wme_rx_queue);
 	DEBUGFS_DEL(wme_tx_queue);
 #endif
+	DEBUGFS_DEL(agg_status);
 
 	debugfs_remove(sta->debugfs.dir);
 	sta->debugfs.dir = NULL;
diff --git a/package/mac80211/src/net/mac80211/event.c b/package/mac80211/src/net/mac80211/event.c
index 68a526cb76..2280f40b45 100644
--- a/package/mac80211/src/net/mac80211/event.c
+++ b/package/mac80211/src/net/mac80211/event.c
@@ -22,13 +22,14 @@ void mac80211_ev_michael_mic_failure(struct net_device *dev, int keyidx,
 {
 	union iwreq_data wrqu;
 	char *buf = kmalloc(128, GFP_ATOMIC);
+	DECLARE_MAC_BUF(mac);
 
 	if (buf) {
 		/* TODO: needed parameters: count, key type, TSC */
 		sprintf(buf, "MLME-MICHAELMICFAILURE.indication("
-			"keyid=%d %scast addr=" MAC_FMT ")",
+			"keyid=%d %scast addr=%s)",
 			keyidx, hdr->addr1[0] & 0x01 ? "broad" : "uni",
-			MAC_ARG(hdr->addr2));
+			print_mac(mac, hdr->addr2));
 		memset(&wrqu, 0, sizeof(wrqu));
 		wrqu.data.length = strlen(buf);
 		wireless_send_event(dev, IWEVCUSTOM, &wrqu, buf);
diff --git a/package/mac80211/src/net/mac80211/ieee80211.c b/package/mac80211/src/net/mac80211/ieee80211.c
index 64fa7204b4..1a0171d2f1 100644
--- a/package/mac80211/src/net/mac80211/ieee80211.c
+++ b/package/mac80211/src/net/mac80211/ieee80211.c
@@ -21,6 +21,7 @@
 #include <linux/wireless.h>
 #include <linux/rtnetlink.h>
 #include <linux/bitmap.h>
+#include <net/net_namespace.h>
 #include <net/cfg80211.h>
 
 #include "ieee80211_i.h"
@@ -33,6 +34,8 @@
 #include "debugfs.h"
 #include "debugfs_netdev.h"
 
+#define SUPP_MCS_SET_LEN 16
+
 /*
  * For seeing transmitted packets on monitor interfaces
  * we have a radiotap header too.
@@ -45,7 +48,7 @@ struct ieee80211_tx_status_rtap_hdr {
 
 /* common interface routines */
 
-static int header_parse_80211(struct sk_buff *skb, unsigned char *haddr)
+static int header_parse_80211(const struct sk_buff *skb, unsigned char *haddr)
 {
 	memcpy(haddr, skb_mac_header(skb) + 10, ETH_ALEN); /* addr2 */
 	return ETH_ALEN;
@@ -64,9 +67,19 @@ static void ieee80211_configure_filter(struct ieee80211_local *local)
 		new_flags |= FIF_ALLMULTI;
 
 	if (local->monitors)
-		new_flags |= FIF_CONTROL |
-			     FIF_OTHER_BSS |
-			     FIF_BCN_PRBRESP_PROMISC;
+		new_flags |= FIF_BCN_PRBRESP_PROMISC;
+
+	if (local->fif_fcsfail)
+		new_flags |= FIF_FCSFAIL;
+
+	if (local->fif_plcpfail)
+		new_flags |= FIF_PLCPFAIL;
+
+	if (local->fif_control)
+		new_flags |= FIF_CONTROL;
+
+	if (local->fif_other_bss)
+		new_flags |= FIF_OTHER_BSS;
 
 	changed_flags = local->filter_flags ^ new_flags;
 
@@ -174,21 +187,21 @@ static int ieee80211_open(struct net_device *dev)
 			/*
 			 * check whether it may have the same address
 			 */
-			if (!identical_mac_addr_allowed(sdata->type,
-							nsdata->type))
+			if (!identical_mac_addr_allowed(sdata->vif.type,
+							nsdata->vif.type))
 				return -ENOTUNIQ;
 
 			/*
 			 * can only add VLANs to enabled APs
 			 */
-			if (sdata->type == IEEE80211_IF_TYPE_VLAN &&
-			    nsdata->type == IEEE80211_IF_TYPE_AP &&
+			if (sdata->vif.type == IEEE80211_IF_TYPE_VLAN &&
+			    nsdata->vif.type == IEEE80211_IF_TYPE_AP &&
 			    netif_running(nsdata->dev))
 				sdata->u.vlan.ap = nsdata;
 		}
 	}
 
-	switch (sdata->type) {
+	switch (sdata->vif.type) {
 	case IEEE80211_IF_TYPE_WDS:
 		if (is_zero_ether_addr(sdata->u.wds.remote_addr))
 			return -ENOLINK;
@@ -215,32 +228,46 @@ static int ieee80211_open(struct net_device *dev)
 			res = local->ops->start(local_to_hw(local));
 		if (res)
 			return res;
+		ieee80211_hw_config(local);
+		ieee80211_led_radio(local, local->hw.conf.radio_enabled);
 	}
 
-	switch (sdata->type) {
+	switch (sdata->vif.type) {
 	case IEEE80211_IF_TYPE_VLAN:
 		list_add(&sdata->u.vlan.list, &sdata->u.vlan.ap->u.ap.vlans);
 		/* no need to tell driver */
 		break;
 	case IEEE80211_IF_TYPE_MNTR:
+		if (sdata->u.mntr_flags & MONITOR_FLAG_COOK_FRAMES) {
+			local->cooked_mntrs++;
+			break;
+		}
+
 		/* must be before the call to ieee80211_configure_filter */
 		local->monitors++;
-		if (local->monitors == 1) {
-			netif_tx_lock_bh(local->mdev);
-			ieee80211_configure_filter(local);
-			netif_tx_unlock_bh(local->mdev);
-
+		if (local->monitors == 1)
 			local->hw.conf.flags |= IEEE80211_CONF_RADIOTAP;
-			ieee80211_hw_config(local);
-		}
+
+		if (sdata->u.mntr_flags & MONITOR_FLAG_FCSFAIL)
+			local->fif_fcsfail++;
+		if (sdata->u.mntr_flags & MONITOR_FLAG_PLCPFAIL)
+			local->fif_plcpfail++;
+		if (sdata->u.mntr_flags & MONITOR_FLAG_CONTROL)
+			local->fif_control++;
+		if (sdata->u.mntr_flags & MONITOR_FLAG_OTHER_BSS)
+			local->fif_other_bss++;
+
+		netif_tx_lock_bh(local->mdev);
+		ieee80211_configure_filter(local);
+		netif_tx_unlock_bh(local->mdev);
 		break;
 	case IEEE80211_IF_TYPE_STA:
 	case IEEE80211_IF_TYPE_IBSS:
 		sdata->u.sta.flags &= ~IEEE80211_STA_PREV_BSSID_SET;
 		/* fall through */
 	default:
-		conf.if_id = dev->ifindex;
-		conf.type = sdata->type;
+		conf.vif = &sdata->vif;
+		conf.type = sdata->vif.type;
 		conf.mac_addr = dev->dev_addr;
 		res = local->ops->add_interface(local_to_hw(local), &conf);
 		if (res && !local->open_count && local->ops->stop)
@@ -252,7 +279,7 @@ static int ieee80211_open(struct net_device *dev)
 		ieee80211_reset_erp_info(dev);
 		ieee80211_enable_keys(sdata);
 
-		if (sdata->type == IEEE80211_IF_TYPE_STA &&
+		if (sdata->vif.type == IEEE80211_IF_TYPE_STA &&
 		    !(sdata->flags & IEEE80211_SDATA_USERSPACE_MLME))
 			netif_carrier_off(dev);
 		else
@@ -266,6 +293,17 @@ static int ieee80211_open(struct net_device *dev)
 		tasklet_enable(&local->tasklet);
 	}
 
+	/*
+	 * set_multicast_list will be invoked by the networking core
+	 * which will check whether any increments here were done in
+	 * error and sync them down to the hardware as filter flags.
+	 */
+	if (sdata->flags & IEEE80211_SDATA_ALLMULTI)
+		atomic_inc(&local->iff_allmultis);
+
+	if (sdata->flags & IEEE80211_SDATA_PROMISC)
+		atomic_inc(&local->iff_promiscs);
+
 	local->open_count++;
 
 	netif_start_queue(dev);
@@ -278,17 +316,47 @@ static int ieee80211_stop(struct net_device *dev)
 	struct ieee80211_sub_if_data *sdata;
 	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
 	struct ieee80211_if_init_conf conf;
+	struct sta_info *sta;
+	int i;
 
 	sdata = IEEE80211_DEV_TO_SUB_IF(dev);
 
+	list_for_each_entry(sta, &local->sta_list, list) {
+		if (sta->dev == dev)
+			for (i = 0; i <  STA_TID_NUM; i++)
+				ieee80211_sta_stop_rx_ba_session(sta->dev,
+						sta->addr, i,
+						WLAN_BACK_RECIPIENT,
+						WLAN_REASON_QSTA_LEAVE_QBSS);
+	}
+
 	netif_stop_queue(dev);
 
+	/*
+	 * Don't count this interface for promisc/allmulti while it
+	 * is down. dev_mc_unsync() will invoke set_multicast_list
+	 * on the master interface which will sync these down to the
+	 * hardware as filter flags.
+	 */
+	if (sdata->flags & IEEE80211_SDATA_ALLMULTI)
+		atomic_dec(&local->iff_allmultis);
+
+	if (sdata->flags & IEEE80211_SDATA_PROMISC)
+		atomic_dec(&local->iff_promiscs);
+
 	dev_mc_unsync(local->mdev, dev);
 
-	/* down all dependent devices, that is VLANs */
-	if (sdata->type == IEEE80211_IF_TYPE_AP) {
+	/* APs need special treatment */
+	if (sdata->vif.type == IEEE80211_IF_TYPE_AP) {
 		struct ieee80211_sub_if_data *vlan, *tmp;
+		struct beacon_data *old_beacon = sdata->u.ap.beacon;
+
+		/* remove beacon */
+		rcu_assign_pointer(sdata->u.ap.beacon, NULL);
+		synchronize_rcu();
+		kfree(old_beacon);
 
+		/* down all dependent devices, that is VLANs */
 		list_for_each_entry_safe(vlan, tmp, &sdata->u.ap.vlans,
 					 u.vlan.list)
 			dev_close(vlan->dev);
@@ -297,22 +365,34 @@ static int ieee80211_stop(struct net_device *dev)
 
 	local->open_count--;
 
-	switch (sdata->type) {
+	switch (sdata->vif.type) {
 	case IEEE80211_IF_TYPE_VLAN:
 		list_del(&sdata->u.vlan.list);
 		sdata->u.vlan.ap = NULL;
 		/* no need to tell driver */
 		break;
 	case IEEE80211_IF_TYPE_MNTR:
-		local->monitors--;
-		if (local->monitors == 0) {
-			netif_tx_lock_bh(local->mdev);
-			ieee80211_configure_filter(local);
-			netif_tx_unlock_bh(local->mdev);
-
-			local->hw.conf.flags |= IEEE80211_CONF_RADIOTAP;
-			ieee80211_hw_config(local);
+		if (sdata->u.mntr_flags & MONITOR_FLAG_COOK_FRAMES) {
+			local->cooked_mntrs--;
+			break;
 		}
+
+		local->monitors--;
+		if (local->monitors == 0)
+			local->hw.conf.flags &= ~IEEE80211_CONF_RADIOTAP;
+
+		if (sdata->u.mntr_flags & MONITOR_FLAG_FCSFAIL)
+			local->fif_fcsfail--;
+		if (sdata->u.mntr_flags & MONITOR_FLAG_PLCPFAIL)
+			local->fif_plcpfail--;
+		if (sdata->u.mntr_flags & MONITOR_FLAG_CONTROL)
+			local->fif_control--;
+		if (sdata->u.mntr_flags & MONITOR_FLAG_OTHER_BSS)
+			local->fif_other_bss--;
+
+		netif_tx_lock_bh(local->mdev);
+		ieee80211_configure_filter(local);
+		netif_tx_unlock_bh(local->mdev);
 		break;
 	case IEEE80211_IF_TYPE_STA:
 	case IEEE80211_IF_TYPE_IBSS:
@@ -327,16 +407,24 @@ static int ieee80211_stop(struct net_device *dev)
 		synchronize_rcu();
 		skb_queue_purge(&sdata->u.sta.skb_queue);
 
-		if (!local->ops->hw_scan &&
-		    local->scan_dev == sdata->dev) {
-			local->sta_scanning = 0;
-			cancel_delayed_work(&local->scan_work);
+		if (local->scan_dev == sdata->dev) {
+			if (!local->ops->hw_scan) {
+				local->sta_sw_scanning = 0;
+				cancel_delayed_work(&local->scan_work);
+			} else
+				local->sta_hw_scanning = 0;
 		}
+
 		flush_workqueue(local->hw.workqueue);
+
+		sdata->u.sta.flags &= ~IEEE80211_STA_PRIVACY_INVOKED;
+		kfree(sdata->u.sta.extra_ie);
+		sdata->u.sta.extra_ie = NULL;
+		sdata->u.sta.extra_ie_len = 0;
 		/* fall through */
 	default:
-		conf.if_id = dev->ifindex;
-		conf.type = sdata->type;
+		conf.vif = &sdata->vif;
+		conf.type = sdata->vif.type;
 		conf.mac_addr = dev->dev_addr;
 		/* disable all keys for as long as this netdev is down */
 		ieee80211_disable_keys(sdata);
@@ -350,6 +438,8 @@ static int ieee80211_stop(struct net_device *dev)
 		if (local->ops->stop)
 			local->ops->stop(local_to_hw(local));
 
+		ieee80211_led_radio(local, 0);
+
 		tasklet_disable(&local->tx_pending_tasklet);
 		tasklet_disable(&local->tasklet);
 	}
@@ -357,6 +447,329 @@ static int ieee80211_stop(struct net_device *dev)
 	return 0;
 }
 
+int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid)
+{
+	struct ieee80211_local *local = hw_to_local(hw);
+	struct sta_info *sta;
+	struct ieee80211_sub_if_data *sdata;
+	u16 start_seq_num = 0;
+	u8 *state;
+	int ret;
+	DECLARE_MAC_BUF(mac);
+
+	if (tid >= STA_TID_NUM)
+		return -EINVAL;
+
+#ifdef CONFIG_MAC80211_HT_DEBUG
+	printk(KERN_DEBUG "Open BA session requested for %s tid %u\n",
+				print_mac(mac, ra), tid);
+#endif /* CONFIG_MAC80211_HT_DEBUG */
+
+	sta = sta_info_get(local, ra);
+	if (!sta) {
+		printk(KERN_DEBUG "Could not find the station\n");
+		return -ENOENT;
+	}
+
+	spin_lock_bh(&sta->ampdu_mlme.ampdu_tx);
+
+	/* we have tried too many times, receiver does not want A-MPDU */
+	if (sta->ampdu_mlme.tid_tx[tid].addba_req_num >	HT_AGG_MAX_RETRIES) {
+		ret = -EBUSY;
+		goto start_ba_exit;
+	}
+
+	state = &sta->ampdu_mlme.tid_tx[tid].state;
+	/* check if the TID is not in aggregation flow already */
+	if (*state != HT_AGG_STATE_IDLE) {
+#ifdef CONFIG_MAC80211_HT_DEBUG
+		printk(KERN_DEBUG "BA request denied - session is not "
+				 "idle on tid %u\n", tid);
+#endif /* CONFIG_MAC80211_HT_DEBUG */
+		ret = -EAGAIN;
+		goto start_ba_exit;
+	}
+
+	/* ensure that TX flow won't interrupt us
+	 * until the end of the call to requeue function */
+	spin_lock_bh(&local->mdev->queue_lock);
+
+	/* create a new queue for this aggregation */
+	ret = ieee80211_ht_agg_queue_add(local, sta, tid);
+
+	/* case no queue is available to aggregation
+	 * don't switch to aggregation */
+	if (ret) {
+#ifdef CONFIG_MAC80211_HT_DEBUG
+		printk(KERN_DEBUG "BA request denied - no queue available for"
+					" tid %d\n", tid);
+#endif /* CONFIG_MAC80211_HT_DEBUG */
+		spin_unlock_bh(&local->mdev->queue_lock);
+		goto start_ba_exit;
+	}
+	sdata = IEEE80211_DEV_TO_SUB_IF(sta->dev);
+
+	/* Ok, the Addba frame hasn't been sent yet, but if the driver calls the
+	 * call back right away, it must see that the flow has begun */
+	*state |= HT_ADDBA_REQUESTED_MSK;
+
+	if (local->ops->ampdu_action)
+		ret = local->ops->ampdu_action(hw, IEEE80211_AMPDU_TX_START,
+						ra, tid, &start_seq_num);
+
+	if (ret) {
+		/* No need to requeue the packets in the agg queue, since we
+		 * held the tx lock: no packet could be enqueued to the newly
+		 * allocated queue */
+		 ieee80211_ht_agg_queue_remove(local, sta, tid, 0);
+#ifdef CONFIG_MAC80211_HT_DEBUG
+		printk(KERN_DEBUG "BA request denied - HW or queue unavailable"
+				" for tid %d\n", tid);
+#endif /* CONFIG_MAC80211_HT_DEBUG */
+		spin_unlock_bh(&local->mdev->queue_lock);
+		*state = HT_AGG_STATE_IDLE;
+		goto start_ba_exit;
+	}
+
+	/* Will put all the packets in the new SW queue */
+	ieee80211_requeue(local, ieee802_1d_to_ac[tid]);
+	spin_unlock_bh(&local->mdev->queue_lock);
+
+	/* We have most probably almost emptied the legacy queue */
+	/* ieee80211_wake_queue(local_to_hw(local), ieee802_1d_to_ac[tid]); */
+
+	/* send an addBA request */
+	sta->ampdu_mlme.dialog_token_allocator++;
+	sta->ampdu_mlme.tid_tx[tid].dialog_token =
+			sta->ampdu_mlme.dialog_token_allocator;
+	sta->ampdu_mlme.tid_tx[tid].ssn = start_seq_num;
+
+	ieee80211_send_addba_request(sta->dev, ra, tid,
+			 sta->ampdu_mlme.tid_tx[tid].dialog_token,
+			 sta->ampdu_mlme.tid_tx[tid].ssn,
+			 0x40, 5000);
+
+	/* activate the timer for the recipient's addBA response */
+	sta->ampdu_mlme.tid_tx[tid].addba_resp_timer.expires =
+				jiffies + ADDBA_RESP_INTERVAL;
+	add_timer(&sta->ampdu_mlme.tid_tx[tid].addba_resp_timer);
+	printk(KERN_DEBUG "activated addBA response timer on tid %d\n", tid);
+
+start_ba_exit:
+	spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx);
+	sta_info_put(sta);
+	return ret;
+}
+EXPORT_SYMBOL(ieee80211_start_tx_ba_session);
+
+int ieee80211_stop_tx_ba_session(struct ieee80211_hw *hw,
+				 u8 *ra, u16 tid,
+				 enum ieee80211_back_parties initiator)
+{
+	struct ieee80211_local *local = hw_to_local(hw);
+	struct sta_info *sta;
+	u8 *state;
+	int ret = 0;
+	DECLARE_MAC_BUF(mac);
+
+	if (tid >= STA_TID_NUM)
+		return -EINVAL;
+
+#ifdef CONFIG_MAC80211_HT_DEBUG
+	printk(KERN_DEBUG "Stop a BA session requested for %s tid %u\n",
+				print_mac(mac, ra), tid);
+#endif /* CONFIG_MAC80211_HT_DEBUG */
+
+	sta = sta_info_get(local, ra);
+	if (!sta)
+		return -ENOENT;
+
+	/* check if the TID is in aggregation */
+	state = &sta->ampdu_mlme.tid_tx[tid].state;
+	spin_lock_bh(&sta->ampdu_mlme.ampdu_tx);
+
+	if (*state != HT_AGG_STATE_OPERATIONAL) {
+#ifdef CONFIG_MAC80211_HT_DEBUG
+		printk(KERN_DEBUG "Try to stop Tx aggregation on"
+				" non active TID\n");
+#endif /* CONFIG_MAC80211_HT_DEBUG */
+		ret = -ENOENT;
+		goto stop_BA_exit;
+	}
+
+	ieee80211_stop_queue(hw, sta->tid_to_tx_q[tid]);
+
+	*state = HT_AGG_STATE_REQ_STOP_BA_MSK |
+		(initiator << HT_AGG_STATE_INITIATOR_SHIFT);
+
+	if (local->ops->ampdu_action)
+		ret = local->ops->ampdu_action(hw, IEEE80211_AMPDU_TX_STOP,
+						ra, tid, NULL);
+
+	/* case HW denied going back to legacy */
+	if (ret) {
+		WARN_ON(ret != -EBUSY);
+		*state = HT_AGG_STATE_OPERATIONAL;
+		ieee80211_wake_queue(hw, sta->tid_to_tx_q[tid]);
+		goto stop_BA_exit;
+	}
+
+stop_BA_exit:
+	spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx);
+	sta_info_put(sta);
+	return ret;
+}
+EXPORT_SYMBOL(ieee80211_stop_tx_ba_session);
+
+void ieee80211_start_tx_ba_cb(struct ieee80211_hw *hw, u8 *ra, u16 tid)
+{
+	struct ieee80211_local *local = hw_to_local(hw);
+	struct sta_info *sta;
+	u8 *state;
+	DECLARE_MAC_BUF(mac);
+
+	if (tid >= STA_TID_NUM) {
+		printk(KERN_DEBUG "Bad TID value: tid = %d (>= %d)\n",
+				tid, STA_TID_NUM);
+		return;
+	}
+
+	sta = sta_info_get(local, ra);
+	if (!sta) {
+		printk(KERN_DEBUG "Could not find station: %s\n",
+				print_mac(mac, ra));
+		return;
+	}
+
+	state = &sta->ampdu_mlme.tid_tx[tid].state;
+	spin_lock_bh(&sta->ampdu_mlme.ampdu_tx);
+
+	if (!(*state & HT_ADDBA_REQUESTED_MSK)) {
+		printk(KERN_DEBUG "addBA was not requested yet, state is %d\n",
+				*state);
+		spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx);
+		sta_info_put(sta);
+		return;
+	}
+
+	WARN_ON_ONCE(*state & HT_ADDBA_DRV_READY_MSK);
+
+	*state |= HT_ADDBA_DRV_READY_MSK;
+
+	if (*state == HT_AGG_STATE_OPERATIONAL) {
+		printk(KERN_DEBUG "Aggregation is on for tid %d \n", tid);
+		ieee80211_wake_queue(hw, sta->tid_to_tx_q[tid]);
+	}
+	spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx);
+	sta_info_put(sta);
+}
+EXPORT_SYMBOL(ieee80211_start_tx_ba_cb);
+
+void ieee80211_stop_tx_ba_cb(struct ieee80211_hw *hw, u8 *ra, u8 tid)
+{
+	struct ieee80211_local *local = hw_to_local(hw);
+	struct sta_info *sta;
+	u8 *state;
+	int agg_queue;
+	DECLARE_MAC_BUF(mac);
+
+	if (tid >= STA_TID_NUM) {
+		printk(KERN_DEBUG "Bad TID value: tid = %d (>= %d)\n",
+				tid, STA_TID_NUM);
+		return;
+	}
+
+	printk(KERN_DEBUG "Stop a BA session requested on DA %s tid %d\n",
+				print_mac(mac, ra), tid);
+
+	sta = sta_info_get(local, ra);
+	if (!sta) {
+		printk(KERN_DEBUG "Could not find station: %s\n",
+				print_mac(mac, ra));
+		return;
+	}
+	state = &sta->ampdu_mlme.tid_tx[tid].state;
+
+	spin_lock_bh(&sta->ampdu_mlme.ampdu_tx);
+	if ((*state & HT_AGG_STATE_REQ_STOP_BA_MSK) == 0) {
+		printk(KERN_DEBUG "unexpected callback to A-MPDU stop\n");
+		sta_info_put(sta);
+		spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx);
+		return;
+	}
+
+	if (*state & HT_AGG_STATE_INITIATOR_MSK)
+		ieee80211_send_delba(sta->dev, ra, tid,
+			WLAN_BACK_INITIATOR, WLAN_REASON_QSTA_NOT_USE);
+
+	agg_queue = sta->tid_to_tx_q[tid];
+
+	/* avoid ordering issues: we are the only one that can modify
+	 * the content of the qdiscs */
+	spin_lock_bh(&local->mdev->queue_lock);
+	/* remove the queue for this aggregation */
+	ieee80211_ht_agg_queue_remove(local, sta, tid, 1);
+	spin_unlock_bh(&local->mdev->queue_lock);
+
+	/* we just requeued the all the frames that were in the removed
+	 * queue, and since we might miss a softirq we do netif_schedule.
+	 * ieee80211_wake_queue is not used here as this queue is not
+	 * necessarily stopped */
+	netif_schedule(local->mdev);
+	*state = HT_AGG_STATE_IDLE;
+	sta->ampdu_mlme.tid_tx[tid].addba_req_num = 0;
+	spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx);
+
+	sta_info_put(sta);
+}
+EXPORT_SYMBOL(ieee80211_stop_tx_ba_cb);
+
+void ieee80211_start_tx_ba_cb_irqsafe(struct ieee80211_hw *hw,
+				      const u8 *ra, u16 tid)
+{
+	struct ieee80211_local *local = hw_to_local(hw);
+	struct ieee80211_ra_tid *ra_tid;
+	struct sk_buff *skb = dev_alloc_skb(0);
+
+	if (unlikely(!skb)) {
+		if (net_ratelimit())
+			printk(KERN_WARNING "%s: Not enough memory, "
+			       "dropping start BA session", skb->dev->name);
+		return;
+	}
+	ra_tid = (struct ieee80211_ra_tid *) &skb->cb;
+	memcpy(&ra_tid->ra, ra, ETH_ALEN);
+	ra_tid->tid = tid;
+
+	skb->pkt_type = IEEE80211_ADDBA_MSG;
+	skb_queue_tail(&local->skb_queue, skb);
+	tasklet_schedule(&local->tasklet);
+}
+EXPORT_SYMBOL(ieee80211_start_tx_ba_cb_irqsafe);
+
+void ieee80211_stop_tx_ba_cb_irqsafe(struct ieee80211_hw *hw,
+				     const u8 *ra, u16 tid)
+{
+	struct ieee80211_local *local = hw_to_local(hw);
+	struct ieee80211_ra_tid *ra_tid;
+	struct sk_buff *skb = dev_alloc_skb(0);
+
+	if (unlikely(!skb)) {
+		if (net_ratelimit())
+			printk(KERN_WARNING "%s: Not enough memory, "
+			       "dropping stop BA session", skb->dev->name);
+		return;
+	}
+	ra_tid = (struct ieee80211_ra_tid *) &skb->cb;
+	memcpy(&ra_tid->ra, ra, ETH_ALEN);
+	ra_tid->tid = tid;
+
+	skb->pkt_type = IEEE80211_DELBA_MSG;
+	skb_queue_tail(&local->skb_queue, skb);
+	tasklet_schedule(&local->tasklet);
+}
+EXPORT_SYMBOL(ieee80211_stop_tx_ba_cb_irqsafe);
+
 static void ieee80211_set_multicast_list(struct net_device *dev)
 {
 	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
@@ -365,8 +778,8 @@ static void ieee80211_set_multicast_list(struct net_device *dev)
 
 	allmulti = !!(dev->flags & IFF_ALLMULTI);
 	promisc = !!(dev->flags & IFF_PROMISC);
-	sdata_allmulti = sdata->flags & IEEE80211_SDATA_ALLMULTI;
-	sdata_promisc = sdata->flags & IEEE80211_SDATA_PROMISC;
+	sdata_allmulti = !!(sdata->flags & IEEE80211_SDATA_ALLMULTI);
+	sdata_promisc = !!(sdata->flags & IEEE80211_SDATA_PROMISC);
 
 	if (allmulti != sdata_allmulti) {
 		if (dev->flags & IFF_ALLMULTI)
@@ -387,6 +800,14 @@ static void ieee80211_set_multicast_list(struct net_device *dev)
 	dev_mc_sync(local->mdev, dev);
 }
 
+static const struct header_ops ieee80211_header_ops = {
+	.create		= eth_header,
+	.parse		= header_parse_80211,
+	.rebuild	= eth_rebuild_header,
+	.cache		= eth_header_cache,
+	.cache_update	= eth_header_cache_update,
+};
+
 /* Must not be called for mdev */
 void ieee80211_if_setup(struct net_device *dev)
 {
@@ -407,6 +828,7 @@ int ieee80211_if_update_wds(struct net_device *dev, u8 *remote_addr)
 	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
 	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
 	struct sta_info *sta;
+	DECLARE_MAC_BUF(mac);
 
 	if (compare_ether_addr(remote_addr, sdata->u.wds.remote_addr) == 0)
 		return 0;
@@ -415,6 +837,9 @@ int ieee80211_if_update_wds(struct net_device *dev, u8 *remote_addr)
 	sta = sta_info_add(local, dev, remote_addr, GFP_KERNEL);
 	if (!sta)
 		return -ENOMEM;
+
+	sta->flags |= WLAN_STA_AUTHORIZED;
+
 	sta_info_put(sta);
 
 	/* Remove STA entry for the old peer */
@@ -424,8 +849,8 @@ int ieee80211_if_update_wds(struct net_device *dev, u8 *remote_addr)
 		sta_info_put(sta);
 	} else {
 		printk(KERN_DEBUG "%s: could not find STA entry for WDS link "
-		       "peer " MAC_FMT "\n",
-		       dev->name, MAC_ARG(sdata->u.wds.remote_addr));
+		       "peer %s\n",
+		       dev->name, print_mac(mac, sdata->u.wds.remote_addr));
 	}
 
 	/* Update WDS link data */
@@ -448,20 +873,20 @@ static int __ieee80211_if_config(struct net_device *dev,
 		return 0;
 
 	memset(&conf, 0, sizeof(conf));
-	conf.type = sdata->type;
-	if (sdata->type == IEEE80211_IF_TYPE_STA ||
-	    sdata->type == IEEE80211_IF_TYPE_IBSS) {
+	conf.type = sdata->vif.type;
+	if (sdata->vif.type == IEEE80211_IF_TYPE_STA ||
+	    sdata->vif.type == IEEE80211_IF_TYPE_IBSS) {
 		conf.bssid = sdata->u.sta.bssid;
 		conf.ssid = sdata->u.sta.ssid;
 		conf.ssid_len = sdata->u.sta.ssid_len;
-	} else if (sdata->type == IEEE80211_IF_TYPE_AP) {
+	} else if (sdata->vif.type == IEEE80211_IF_TYPE_AP) {
 		conf.ssid = sdata->u.ap.ssid;
 		conf.ssid_len = sdata->u.ap.ssid_len;
 		conf.beacon = beacon;
 		conf.beacon_control = control;
 	}
 	return local->ops->config_interface(local_to_hw(local),
-					   dev->ifindex, &conf);
+					    &sdata->vif, &conf);
 }
 
 int ieee80211_if_config(struct net_device *dev)
@@ -473,11 +898,13 @@ int ieee80211_if_config_beacon(struct net_device *dev)
 {
 	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
 	struct ieee80211_tx_control control;
+	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
 	struct sk_buff *skb;
 
 	if (!(local->hw.flags & IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE))
 		return 0;
-	skb = ieee80211_beacon_get(local_to_hw(local), dev->ifindex, &control);
+	skb = ieee80211_beacon_get(local_to_hw(local), &sdata->vif,
+				   &control);
 	if (!skb)
 		return -ENOMEM;
 	return __ieee80211_if_config(dev, skb, &control);
@@ -485,37 +912,28 @@ int ieee80211_if_config_beacon(struct net_device *dev)
 
 int ieee80211_hw_config(struct ieee80211_local *local)
 {
-	struct ieee80211_hw_mode *mode;
 	struct ieee80211_channel *chan;
 	int ret = 0;
 
-	if (local->sta_scanning) {
+	if (local->sta_sw_scanning)
 		chan = local->scan_channel;
-		mode = local->scan_hw_mode;
-	} else {
+	else
 		chan = local->oper_channel;
-		mode = local->oper_hw_mode;
-	}
 
-	local->hw.conf.channel = chan->chan;
-	local->hw.conf.channel_val = chan->val;
-	if (!local->hw.conf.power_level) {
-		local->hw.conf.power_level = chan->power_level;
-	} else {
-		local->hw.conf.power_level = min(chan->power_level,
-						 local->hw.conf.power_level);
-	}
-	local->hw.conf.freq = chan->freq;
-	local->hw.conf.phymode = mode->mode;
-	local->hw.conf.antenna_max = chan->antenna_max;
-	local->hw.conf.chan = chan;
-	local->hw.conf.mode = mode;
+	local->hw.conf.channel = chan;
+
+	if (!local->hw.conf.power_level)
+		local->hw.conf.power_level = chan->max_power;
+	else
+		local->hw.conf.power_level = min(chan->max_power,
+					       local->hw.conf.power_level);
+
+	local->hw.conf.max_antenna_gain = chan->max_antenna_gain;
 
 #ifdef CONFIG_MAC80211_VERBOSE_DEBUG
-	printk(KERN_DEBUG "HW CONFIG: channel=%d freq=%d "
-	       "phymode=%d\n", local->hw.conf.channel, local->hw.conf.freq,
-	       local->hw.conf.phymode);
-#endif /* CONFIG_MAC80211_VERBOSE_DEBUG */
+	printk(KERN_DEBUG "%s: HW CONFIG: freq=%d\n",
+	       wiphy_name(local->hw.wiphy), chan->center_freq);
+#endif
 
 	if (local->open_count)
 		ret = local->ops->config(local_to_hw(local), &local->hw.conf);
@@ -523,25 +941,81 @@ int ieee80211_hw_config(struct ieee80211_local *local)
 	return ret;
 }
 
-void ieee80211_erp_info_change_notify(struct net_device *dev, u8 changes)
+/**
+ * ieee80211_hw_config_ht should be used only after legacy configuration
+ * has been determined, as ht configuration depends upon the hardware's
+ * HT abilities for a _specific_ band.
+ */
+int ieee80211_hw_config_ht(struct ieee80211_local *local, int enable_ht,
+			   struct ieee80211_ht_info *req_ht_cap,
+			   struct ieee80211_ht_bss_info *req_bss_cap)
 {
-	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
-	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-	if (local->ops->erp_ie_changed)
-		local->ops->erp_ie_changed(local_to_hw(local), changes,
-			!!(sdata->flags & IEEE80211_SDATA_USE_PROTECTION),
-			!(sdata->flags & IEEE80211_SDATA_SHORT_PREAMBLE));
+	struct ieee80211_conf *conf = &local->hw.conf;
+	struct ieee80211_supported_band *sband;
+	int i;
+
+	sband = local->hw.wiphy->bands[conf->channel->band];
+
+	/* HT is not supported */
+	if (!sband->ht_info.ht_supported) {
+		conf->flags &= ~IEEE80211_CONF_SUPPORT_HT_MODE;
+		return -EOPNOTSUPP;
+	}
+
+	/* disable HT */
+	if (!enable_ht) {
+		conf->flags &= ~IEEE80211_CONF_SUPPORT_HT_MODE;
+	} else {
+		conf->flags |= IEEE80211_CONF_SUPPORT_HT_MODE;
+		conf->ht_conf.cap = req_ht_cap->cap & sband->ht_info.cap;
+		conf->ht_conf.cap &= ~(IEEE80211_HT_CAP_MIMO_PS);
+		conf->ht_conf.cap |=
+			sband->ht_info.cap & IEEE80211_HT_CAP_MIMO_PS;
+		conf->ht_bss_conf.primary_channel =
+			req_bss_cap->primary_channel;
+		conf->ht_bss_conf.bss_cap = req_bss_cap->bss_cap;
+		conf->ht_bss_conf.bss_op_mode = req_bss_cap->bss_op_mode;
+		for (i = 0; i < SUPP_MCS_SET_LEN; i++)
+			conf->ht_conf.supp_mcs_set[i] =
+				sband->ht_info.supp_mcs_set[i] &
+				  req_ht_cap->supp_mcs_set[i];
+
+		/* In STA mode, this gives us indication
+		 * to the AP's mode of operation */
+		conf->ht_conf.ht_supported = 1;
+		conf->ht_conf.ampdu_factor = req_ht_cap->ampdu_factor;
+		conf->ht_conf.ampdu_density = req_ht_cap->ampdu_density;
+	}
+
+	local->ops->conf_ht(local_to_hw(local), &local->hw.conf);
+
+	return 0;
+}
+
+void ieee80211_bss_info_change_notify(struct ieee80211_sub_if_data *sdata,
+				      u32 changed)
+{
+	struct ieee80211_local *local = sdata->local;
+
+	if (!changed)
+		return;
+
+	if (local->ops->bss_info_changed)
+		local->ops->bss_info_changed(local_to_hw(local),
+					     &sdata->vif,
+					     &sdata->bss_conf,
+					     changed);
 }
 
 void ieee80211_reset_erp_info(struct net_device *dev)
 {
 	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
 
-	sdata->flags &= ~(IEEE80211_SDATA_USE_PROTECTION |
-			IEEE80211_SDATA_SHORT_PREAMBLE);
-	ieee80211_erp_info_change_notify(dev,
-					 IEEE80211_ERP_CHANGE_PROTECTION |
-					 IEEE80211_ERP_CHANGE_PREAMBLE);
+	sdata->bss_conf.use_cts_prot = 0;
+	sdata->bss_conf.use_short_preamble = 0;
+	ieee80211_bss_info_change_notify(sdata,
+					 BSS_CHANGED_ERP_CTS_PROT |
+					 BSS_CHANGED_ERP_PREAMBLE);
 }
 
 void ieee80211_tx_status_irqsafe(struct ieee80211_hw *hw,
@@ -591,6 +1065,7 @@ static void ieee80211_tasklet_handler(unsigned long data)
 	struct sk_buff *skb;
 	struct ieee80211_rx_status rx_status;
 	struct ieee80211_tx_status *tx_status;
+	struct ieee80211_ra_tid *ra_tid;
 
 	while ((skb = skb_dequeue(&local->skb_queue)) ||
 	       (skb = skb_dequeue(&local->skb_queue_unreliable))) {
@@ -598,7 +1073,7 @@ static void ieee80211_tasklet_handler(unsigned long data)
 		case IEEE80211_RX_MSG:
 			/* status is in skb->cb */
 			memcpy(&rx_status, skb->cb, sizeof(rx_status));
-			/* Clear skb->type in order to not confuse kernel
+			/* Clear skb->pkt_type in order to not confuse kernel
 			 * netstack. */
 			skb->pkt_type = 0;
 			__ieee80211_rx(local_to_hw(local), skb, &rx_status);
@@ -611,6 +1086,18 @@ static void ieee80211_tasklet_handler(unsigned long data)
 					    skb, tx_status);
 			kfree(tx_status);
 			break;
+		case IEEE80211_DELBA_MSG:
+			ra_tid = (struct ieee80211_ra_tid *) &skb->cb;
+			ieee80211_stop_tx_ba_cb(local_to_hw(local),
+						ra_tid->ra, ra_tid->tid);
+			dev_kfree_skb(skb);
+			break;
+		case IEEE80211_ADDBA_MSG:
+			ra_tid = (struct ieee80211_ra_tid *) &skb->cb;
+			ieee80211_start_tx_ba_cb(local_to_hw(local),
+						 ra_tid->ra, ra_tid->tid);
+			dev_kfree_skb(skb);
+			break ;
 		default: /* should never get here! */
 			printk(KERN_ERR "%s: Unknown message type (%d)\n",
 			       wiphy_name(local->hw.wiphy), skb->pkt_type);
@@ -633,7 +1120,7 @@ static void ieee80211_remove_tx_extra(struct ieee80211_local *local,
 	struct ieee80211_tx_packet_data *pkt_data;
 
 	pkt_data = (struct ieee80211_tx_packet_data *)skb->cb;
-	pkt_data->ifindex = control->ifindex;
+	pkt_data->ifindex = vif_to_sdata(control->vif)->dev->ifindex;
 	pkt_data->flags = 0;
 	if (control->flags & IEEE80211_TXCTL_REQ_TX_STATUS)
 		pkt_data->flags |= IEEE80211_TXPD_REQ_TX_STATUS;
@@ -641,6 +1128,8 @@ static void ieee80211_remove_tx_extra(struct ieee80211_local *local,
 		pkt_data->flags |= IEEE80211_TXPD_DO_NOT_ENCRYPT;
 	if (control->flags & IEEE80211_TXCTL_REQUEUE)
 		pkt_data->flags |= IEEE80211_TXPD_REQUEUE;
+	if (control->flags & IEEE80211_TXCTL_EAPOL_FRAME)
+		pkt_data->flags |= IEEE80211_TXPD_EAPOL_FRAME;
 	pkt_data->queue = control->queue;
 
 	hdrlen = ieee80211_get_hdrlen_from_skb(skb);
@@ -695,7 +1184,7 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb,
 	u16 frag, type;
 	struct ieee80211_tx_status_rtap_hdr *rthdr;
 	struct ieee80211_sub_if_data *sdata;
-	int monitors;
+	struct net_device *prev_dev = NULL;
 
 	if (!status) {
 		printk(KERN_ERR
@@ -768,10 +1257,8 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb,
 			sta_info_put(sta);
 			return;
 		}
-	} else {
-		/* FIXME: STUPID to call this with both local and local->mdev */
-		rate_control_tx_status(local, local->mdev, skb, status);
-	}
+	} else
+		rate_control_tx_status(local->mdev, skb, status);
 
 	ieee80211_led_tx(local, 0);
 
@@ -810,7 +1297,11 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb,
 	/* this was a transmitted frame, but now we want to reuse it */
 	skb_orphan(skb);
 
-	if (!local->monitors) {
+	/*
+	 * This is a bit racy but we can avoid a lot of work
+	 * with this test...
+	 */
+	if (!local->monitors && !local->cooked_mntrs) {
 		dev_kfree_skb(skb);
 		return;
 	}
@@ -844,42 +1335,37 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb,
 
 	rthdr->data_retries = status->retry_count;
 
+	/* XXX: is this sufficient for BPF? */
+	skb_set_mac_header(skb, 0);
+	skb->ip_summed = CHECKSUM_UNNECESSARY;
+	skb->pkt_type = PACKET_OTHERHOST;
+	skb->protocol = htons(ETH_P_802_2);
+	memset(skb->cb, 0, sizeof(skb->cb));
+
 	rcu_read_lock();
-	monitors = local->monitors;
 	list_for_each_entry_rcu(sdata, &local->interfaces, list) {
-		/*
-		 * Using the monitors counter is possibly racy, but
-		 * if the value is wrong we simply either clone the skb
-		 * once too much or forget sending it to one monitor iface
-		 * The latter case isn't nice but fixing the race is much
-		 * more complicated.
-		 */
-		if (!monitors || !skb)
-			goto out;
-
-		if (sdata->type == IEEE80211_IF_TYPE_MNTR) {
+		if (sdata->vif.type == IEEE80211_IF_TYPE_MNTR) {
 			if (!netif_running(sdata->dev))
 				continue;
-			monitors--;
-			if (monitors)
+
+			if (prev_dev) {
 				skb2 = skb_clone(skb, GFP_ATOMIC);
-			else
-				skb2 = NULL;
-			skb->dev = sdata->dev;
-			/* XXX: is this sufficient for BPF? */
-			skb_set_mac_header(skb, 0);
-			skb->ip_summed = CHECKSUM_UNNECESSARY;
-			skb->pkt_type = PACKET_OTHERHOST;
-			skb->protocol = htons(ETH_P_802_2);
-			memset(skb->cb, 0, sizeof(skb->cb));
-			netif_rx(skb);
-			skb = skb2;
+				if (skb2) {
+					skb2->dev = prev_dev;
+					netif_rx(skb2);
+				}
+			}
+
+			prev_dev = sdata->dev;
 		}
 	}
- out:
+	if (prev_dev) {
+		skb->dev = prev_dev;
+		netif_rx(skb);
+		skb = NULL;
+	}
 	rcu_read_unlock();
-	if (skb)
-		dev_kfree_skb(skb);
+	dev_kfree_skb(skb);
 }
 EXPORT_SYMBOL(ieee80211_tx_status);
 
@@ -949,9 +1435,6 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
 	local->hw.queues = 1; /* default */
 
 	local->mdev = mdev;
-	local->rx_pre_handlers = ieee80211_rx_pre_handlers;
-	local->rx_handlers = ieee80211_rx_handlers;
-	local->tx_handlers = ieee80211_tx_handlers;
 
 	local->bridge_packets = 1;
 
@@ -961,10 +1444,6 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
 	local->long_retry_limit = 4;
 	local->hw.conf.radio_enabled = 1;
 
-	local->enabled_modes = ~0;
-
-	INIT_LIST_HEAD(&local->modes_list);
-
 	INIT_LIST_HEAD(&local->interfaces);
 
 	INIT_DELAYED_WORK(&local->scan_work, ieee80211_sta_scan_work);
@@ -976,10 +1455,10 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
 	mdev->open = ieee80211_master_open;
 	mdev->stop = ieee80211_master_stop;
 	mdev->type = ARPHRD_IEEE80211;
-	mdev->hard_header_parse = header_parse_80211;
+	mdev->header_ops = &ieee80211_header_ops;
 	mdev->set_multicast_list = ieee80211_master_set_multicast_list;
 
-	sdata->type = IEEE80211_IF_TYPE_AP;
+	sdata->vif.type = IEEE80211_IF_TYPE_AP;
 	sdata->dev = mdev;
 	sdata->local = local;
 	sdata->u.ap.force_unicast_rateidx = -1;
@@ -1009,6 +1488,25 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
 	struct ieee80211_local *local = hw_to_local(hw);
 	const char *name;
 	int result;
+	enum ieee80211_band band;
+
+	/*
+	 * generic code guarantees at least one band,
+	 * set this very early because much code assumes
+	 * that hw.conf.channel is assigned
+	 */
+	for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
+		struct ieee80211_supported_band *sband;
+
+		sband = local->hw.wiphy->bands[band];
+		if (sband) {
+			/* init channel we're on */
+			local->hw.conf.channel =
+			local->oper_channel =
+			local->scan_channel = &sband->channels[0];
+			break;
+		}
+	}
 
 	result = wiphy_register(local->hw.wiphy);
 	if (result < 0)
@@ -1061,7 +1559,8 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
 	ieee80211_debugfs_add_netdev(IEEE80211_DEV_TO_SUB_IF(local->mdev));
 	ieee80211_if_set_type(local->mdev, IEEE80211_IF_TYPE_AP);
 
-	result = ieee80211_init_rate_ctrl_alg(local, NULL);
+	result = ieee80211_init_rate_ctrl_alg(local,
+					      hw->rate_control_algorithm);
 	if (result < 0) {
 		printk(KERN_DEBUG "%s: Failed to initialize rate control "
 		       "algorithm\n", wiphy_name(local->hw.wiphy));
@@ -1109,44 +1608,10 @@ fail_workqueue:
 }
 EXPORT_SYMBOL(ieee80211_register_hw);
 
-int ieee80211_register_hwmode(struct ieee80211_hw *hw,
-			      struct ieee80211_hw_mode *mode)
-{
-	struct ieee80211_local *local = hw_to_local(hw);
-	struct ieee80211_rate *rate;
-	int i;
-
-	INIT_LIST_HEAD(&mode->list);
-	list_add_tail(&mode->list, &local->modes_list);
-
-	local->hw_modes |= (1 << mode->mode);
-	for (i = 0; i < mode->num_rates; i++) {
-		rate = &(mode->rates[i]);
-		rate->rate_inv = CHAN_UTIL_RATE_LCM / rate->rate;
-	}
-	ieee80211_prepare_rates(local, mode);
-
-	if (!local->oper_hw_mode) {
-		/* Default to this mode */
-		local->hw.conf.phymode = mode->mode;
-		local->oper_hw_mode = local->scan_hw_mode = mode;
-		local->oper_channel = local->scan_channel = &mode->channels[0];
-		local->hw.conf.mode = local->oper_hw_mode;
-		local->hw.conf.chan = local->oper_channel;
-	}
-
-	if (!(hw->flags & IEEE80211_HW_DEFAULT_REG_DOMAIN_CONFIGURED))
-		ieee80211_set_default_regdomain(mode);
-
-	return 0;
-}
-EXPORT_SYMBOL(ieee80211_register_hwmode);
-
 void ieee80211_unregister_hw(struct ieee80211_hw *hw)
 {
 	struct ieee80211_local *local = hw_to_local(hw);
 	struct ieee80211_sub_if_data *sdata, *tmp;
-	int i;
 
 	tasklet_kill(&local->tx_pending_tasklet);
 	tasklet_kill(&local->tasklet);
@@ -1187,11 +1652,6 @@ void ieee80211_unregister_hw(struct ieee80211_hw *hw)
 	rate_control_deinitialize(local);
 	debugfs_hw_del(local);
 
-	for (i = 0; i < NUM_IEEE80211_MODES; i++) {
-		kfree(local->supp_rates[i]);
-		kfree(local->basic_rates[i]);
-	}
-
 	if (skb_queue_len(&local->skb_queue)
 			|| skb_queue_len(&local->skb_queue_unreliable))
 		printk(KERN_WARNING "%s: skb_queue not empty\n",
@@ -1222,21 +1682,38 @@ static int __init ieee80211_init(void)
 
 	BUILD_BUG_ON(sizeof(struct ieee80211_tx_packet_data) > sizeof(skb->cb));
 
+	ret = rc80211_simple_init();
+	if (ret)
+		goto out;
+
+	ret = rc80211_pid_init();
+	if (ret)
+		goto out_cleanup_simple;
+
 	ret = ieee80211_wme_register();
 	if (ret) {
 		printk(KERN_DEBUG "ieee80211_init: failed to "
 		       "initialize WME (err=%d)\n", ret);
-		return ret;
+		goto out_cleanup_pid;
 	}
 
 	ieee80211_debugfs_netdev_init();
-	ieee80211_regdomain_init();
 
 	return 0;
+
+ out_cleanup_pid:
+	rc80211_pid_exit();
+ out_cleanup_simple:
+	rc80211_simple_exit();
+ out:
+	return ret;
 }
 
 static void __exit ieee80211_exit(void)
 {
+	rc80211_simple_exit();
+	rc80211_pid_exit();
+
 	ieee80211_wme_unregister();
 	ieee80211_debugfs_netdev_exit();
 }
diff --git a/package/mac80211/src/net/mac80211/ieee80211_common.h b/package/mac80211/src/net/mac80211/ieee80211_common.h
deleted file mode 100644
index c15295d43d..0000000000
--- a/package/mac80211/src/net/mac80211/ieee80211_common.h
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- * IEEE 802.11 driver (80211.o) -- hostapd interface
- * Copyright 2002-2004, Instant802 Networks, Inc.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#ifndef IEEE80211_COMMON_H
-#define IEEE80211_COMMON_H
-
-#include <linux/types.h>
-
-/*
- * This is common header information with user space. It is used on all
- * frames sent to wlan#ap interface.
- */
-
-#define IEEE80211_FI_VERSION 0x80211001
-
-struct ieee80211_frame_info {
-	__be32 version;
-	__be32 length;
-	__be64 mactime;
-	__be64 hosttime;
-	__be32 phytype;
-	__be32 channel;
-	__be32 datarate;
-	__be32 antenna;
-	__be32 priority;
-	__be32 ssi_type;
-	__be32 ssi_signal;
-	__be32 ssi_noise;
-	__be32 preamble;
-	__be32 encoding;
-
-	/* Note: this structure is otherwise identical to capture format used
-	 * in linux-wlan-ng, but this additional field is used to provide meta
-	 * data about the frame to hostapd. This was the easiest method for
-	 * providing this information, but this might change in the future. */
-	__be32 msg_type;
-} __attribute__ ((packed));
-
-
-enum ieee80211_msg_type {
-	ieee80211_msg_normal = 0,
-	ieee80211_msg_tx_callback_ack = 1,
-	ieee80211_msg_tx_callback_fail = 2,
-	/* hole at 3, was ieee80211_msg_passive_scan but unused */
-	/* hole at 4, was ieee80211_msg_wep_frame_unknown_key but now unused */
-	ieee80211_msg_michael_mic_failure = 5,
-	/* hole at 6, was monitor but never sent to userspace */
-	ieee80211_msg_sta_not_assoc = 7,
-	/* 8 was ieee80211_msg_set_aid_for_sta */
-	/* 9 was ieee80211_msg_key_threshold_notification */
-	/* 11 was ieee80211_msg_radar */
-};
-
-struct ieee80211_msg_key_notification {
-	int tx_rx_count;
-	char ifname[IFNAMSIZ];
-	u8 addr[ETH_ALEN]; /* ff:ff:ff:ff:ff:ff for broadcast keys */
-};
-
-
-enum ieee80211_phytype {
-	ieee80211_phytype_fhss_dot11_97  = 1,
-	ieee80211_phytype_dsss_dot11_97  = 2,
-	ieee80211_phytype_irbaseband     = 3,
-	ieee80211_phytype_dsss_dot11_b   = 4,
-	ieee80211_phytype_pbcc_dot11_b   = 5,
-	ieee80211_phytype_ofdm_dot11_g   = 6,
-	ieee80211_phytype_pbcc_dot11_g   = 7,
-	ieee80211_phytype_ofdm_dot11_a   = 8,
-};
-
-enum ieee80211_ssi_type {
-	ieee80211_ssi_none = 0,
-	ieee80211_ssi_norm = 1, /* normalized, 0-1000 */
-	ieee80211_ssi_dbm = 2,
-	ieee80211_ssi_raw = 3, /* raw SSI */
-};
-
-struct ieee80211_radar_info {
-		int channel;
-		int radar;
-		int radar_type;
-};
-
-#endif /* IEEE80211_COMMON_H */
diff --git a/package/mac80211/src/net/mac80211/ieee80211_i.h b/package/mac80211/src/net/mac80211/ieee80211_i.h
index d34a9deca6..1b4a449703 100644
--- a/package/mac80211/src/net/mac80211/ieee80211_i.h
+++ b/package/mac80211/src/net/mac80211/ieee80211_i.h
@@ -37,8 +37,6 @@
 
 struct ieee80211_local;
 
-#define BIT(x) (1 << (x))
-
 #define IEEE80211_ALIGN32_PAD(a) ((4 - ((a) & 3)) & 3)
 
 /* Maximum number of broadcast/multicast frames to buffer when some of the
@@ -81,8 +79,7 @@ struct ieee80211_sta_bss {
 	u8 ssid[IEEE80211_MAX_SSID_LEN];
 	size_t ssid_len;
 	u16 capability; /* host byte order */
-	int hw_mode;
-	int channel;
+	enum ieee80211_band band;
 	int freq;
 	int rssi, signal, noise;
 	u8 *wpa_ie;
@@ -91,6 +88,8 @@ struct ieee80211_sta_bss {
 	size_t rsn_ie_len;
 	u8 *wmm_ie;
 	size_t wmm_ie_len;
+	u8 *ht_ie;
+	size_t ht_ie_len;
 #define IEEE80211_MAX_SUPP_RATES 32
 	u8 supp_rates[IEEE80211_MAX_SUPP_RATES];
 	size_t supp_rates_len;
@@ -109,9 +108,17 @@ struct ieee80211_sta_bss {
 };
 
 
-typedef enum {
-	TXRX_CONTINUE, TXRX_DROP, TXRX_QUEUED
-} ieee80211_txrx_result;
+typedef unsigned __bitwise__ ieee80211_tx_result;
+#define TX_CONTINUE	((__force ieee80211_tx_result) 0u)
+#define TX_DROP		((__force ieee80211_tx_result) 1u)
+#define TX_QUEUED	((__force ieee80211_tx_result) 2u)
+
+typedef unsigned __bitwise__ ieee80211_rx_result;
+#define RX_CONTINUE		((__force ieee80211_rx_result) 0u)
+#define RX_DROP_UNUSABLE	((__force ieee80211_rx_result) 1u)
+#define RX_DROP_MONITOR		((__force ieee80211_rx_result) 2u)
+#define RX_QUEUED		((__force ieee80211_rx_result) 3u)
+
 
 /* flags used in struct ieee80211_txrx_data.flags */
 /* whether the MSDU was fragmented */
@@ -123,6 +130,8 @@ typedef enum {
 /* frame is destined to interface currently processed (incl. multicast frames) */
 #define IEEE80211_TXRXD_RXRA_MATCH		BIT(5)
 #define IEEE80211_TXRXD_TX_INJECTED		BIT(6)
+#define IEEE80211_TXRXD_RX_AMSDU		BIT(7)
+#define IEEE80211_TXRXD_RX_CMNTR_REPORTED	BIT(8)
 struct ieee80211_txrx_data {
 	struct sk_buff *skb;
 	struct net_device *dev;
@@ -135,13 +144,12 @@ struct ieee80211_txrx_data {
 	union {
 		struct {
 			struct ieee80211_tx_control *control;
-			struct ieee80211_hw_mode *mode;
+			struct ieee80211_channel *channel;
 			struct ieee80211_rate *rate;
 			/* use this rate (if set) for last fragment; rate can
 			 * be set to lower rate for the first fragments, e.g.,
 			 * when using CTS protection with IEEE 802.11g. */
 			struct ieee80211_rate *last_frag_rate;
-			int last_frag_hwrate;
 
 			/* Extra fragments (in addition to the first fragment
 			 * in skb) */
@@ -150,6 +158,7 @@ struct ieee80211_txrx_data {
 		} tx;
 		struct {
 			struct ieee80211_rx_status *status;
+			struct ieee80211_rate *rate;
 			int sent_ps_buffered;
 			int queue;
 			int load;
@@ -163,6 +172,8 @@ struct ieee80211_txrx_data {
 #define IEEE80211_TXPD_REQ_TX_STATUS	BIT(0)
 #define IEEE80211_TXPD_DO_NOT_ENCRYPT	BIT(1)
 #define IEEE80211_TXPD_REQUEUE		BIT(2)
+#define IEEE80211_TXPD_EAPOL_FRAME	BIT(3)
+#define IEEE80211_TXPD_AMPDU		BIT(4)
 /* Stored in sk_buff->cb */
 struct ieee80211_tx_packet_data {
 	int ifindex;
@@ -176,21 +187,18 @@ struct ieee80211_tx_stored_packet {
 	struct sk_buff *skb;
 	int num_extra_frag;
 	struct sk_buff **extra_frag;
-	int last_frag_rateidx;
-	int last_frag_hwrate;
 	struct ieee80211_rate *last_frag_rate;
 	unsigned int last_frag_rate_ctrl_probe;
 };
 
-typedef ieee80211_txrx_result (*ieee80211_tx_handler)
-(struct ieee80211_txrx_data *tx);
-
-typedef ieee80211_txrx_result (*ieee80211_rx_handler)
-(struct ieee80211_txrx_data *rx);
+struct beacon_data {
+	u8 *head, *tail;
+	int head_len, tail_len;
+	int dtim_period;
+};
 
 struct ieee80211_if_ap {
-	u8 *beacon_head, *beacon_tail;
-	int beacon_head_len, beacon_tail_len;
+	struct beacon_data *beacon;
 
 	struct list_head vlans;
 
@@ -203,7 +211,7 @@ struct ieee80211_if_ap {
 	u8 tim[sizeof(unsigned long) * BITS_TO_LONGS(IEEE80211_MAX_AID + 1)];
 	atomic_t num_sta_ps; /* number of stations in PS mode */
 	struct sk_buff_head ps_bc_buf;
-	int dtim_period, dtim_count;
+	int dtim_count;
 	int force_unicast_rateidx; /* forced TX rateidx for unicast frames */
 	int max_ratectrl_rateidx; /* max TX rateidx for rate control */
 	int num_beacons; /* number of TXed beacon frames for this BSS */
@@ -232,6 +240,7 @@ struct ieee80211_if_vlan {
 #define IEEE80211_STA_AUTO_SSID_SEL	BIT(10)
 #define IEEE80211_STA_AUTO_BSSID_SEL	BIT(11)
 #define IEEE80211_STA_AUTO_CHANNEL_SEL	BIT(12)
+#define IEEE80211_STA_PRIVACY_INVOKED	BIT(13)
 struct ieee80211_if_sta {
 	enum {
 		IEEE80211_DISABLED, IEEE80211_AUTHENTICATE,
@@ -243,6 +252,8 @@ struct ieee80211_if_sta {
 	u8 bssid[ETH_ALEN], prev_bssid[ETH_ALEN];
 	u8 ssid[IEEE80211_MAX_SSID_LEN];
 	size_t ssid_len;
+	u8 scan_ssid[IEEE80211_MAX_SSID_LEN];
+	size_t scan_ssid_len;
 	u16 aid;
 	u16 ap_capab, capab;
 	u8 *extra_ie; /* to be added to the end of AssocReq */
@@ -261,7 +272,6 @@ struct ieee80211_if_sta {
 	unsigned long request;
 	struct sk_buff_head skb_queue;
 
-	int key_management_enabled;
 	unsigned long last_probe;
 
 #define IEEE80211_AUTH_ALG_OPEN BIT(0)
@@ -273,7 +283,7 @@ struct ieee80211_if_sta {
 
 	unsigned long ibss_join_req;
 	struct sk_buff *probe_resp; /* ProbeResp template for IBSS */
-	u32 supp_rates_bits;
+	u32 supp_rates_bits[IEEE80211_NUM_BANDS];
 
 	int wmm_last_param_set;
 };
@@ -282,15 +292,10 @@ struct ieee80211_if_sta {
 /* flags used in struct ieee80211_sub_if_data.flags */
 #define IEEE80211_SDATA_ALLMULTI	BIT(0)
 #define IEEE80211_SDATA_PROMISC		BIT(1)
-#define IEEE80211_SDATA_USE_PROTECTION	BIT(2) /* CTS protect ERP frames */
-/* use short preamble with IEEE 802.11b: this flag is set when the AP or beacon
- * generator reports that there are no present stations that cannot support short
- * preambles */
-#define IEEE80211_SDATA_SHORT_PREAMBLE	BIT(3)
-#define IEEE80211_SDATA_USERSPACE_MLME	BIT(4)
+#define IEEE80211_SDATA_USERSPACE_MLME	BIT(2)
+#define IEEE80211_SDATA_OPERATING_GMODE	BIT(3)
 struct ieee80211_sub_if_data {
 	struct list_head list;
-	enum ieee80211_if_types type;
 
 	struct wireless_dev wdev;
 
@@ -303,11 +308,11 @@ struct ieee80211_sub_if_data {
 	unsigned int flags;
 
 	int drop_unencrypted;
-	int eapol; /* 0 = process EAPOL frames as normal data frames,
-		    * 1 = send EAPOL frames through wlan#ap to hostapd
-		    *     (default) */
-	int ieee802_1x; /* IEEE 802.1X PAE - drop packet to/from unauthorized
-			 * port */
+
+	/*
+	 * basic rates of this AP or the AP we're associated to
+	 */
+	u64 basic_rates;
 
 	u16 sequence;
 
@@ -319,6 +324,15 @@ struct ieee80211_sub_if_data {
 	struct ieee80211_key *keys[NUM_DEFAULT_KEYS];
 	struct ieee80211_key *default_key;
 
+	/*
+	 * BSS configuration for this interface.
+	 *
+	 * FIXME: I feel bad putting this here when we already have a
+	 *	  bss pointer, but the bss pointer is just wrong when
+	 *	  you have multiple virtual STA mode interfaces...
+	 *	  This needs to be fixed.
+	 */
+	struct ieee80211_bss_conf bss_conf;
 	struct ieee80211_if_ap *bss; /* BSS that this device belongs to */
 
 	union {
@@ -326,6 +340,7 @@ struct ieee80211_sub_if_data {
 		struct ieee80211_if_wds wds;
 		struct ieee80211_if_vlan vlan;
 		struct ieee80211_if_sta sta;
+		u32 mntr_flags;
 	} u;
 	int channel_use;
 	int channel_use_raw;
@@ -336,8 +351,6 @@ struct ieee80211_sub_if_data {
 		struct {
 			struct dentry *channel_use;
 			struct dentry *drop_unencrypted;
-			struct dentry *eapol;
-			struct dentry *ieee8021_x;
 			struct dentry *state;
 			struct dentry *bssid;
 			struct dentry *prev_bssid;
@@ -356,30 +369,21 @@ struct ieee80211_sub_if_data {
 		struct {
 			struct dentry *channel_use;
 			struct dentry *drop_unencrypted;
-			struct dentry *eapol;
-			struct dentry *ieee8021_x;
 			struct dentry *num_sta_ps;
-			struct dentry *dtim_period;
 			struct dentry *dtim_count;
 			struct dentry *num_beacons;
 			struct dentry *force_unicast_rateidx;
 			struct dentry *max_ratectrl_rateidx;
 			struct dentry *num_buffered_multicast;
-			struct dentry *beacon_head_len;
-			struct dentry *beacon_tail_len;
 		} ap;
 		struct {
 			struct dentry *channel_use;
 			struct dentry *drop_unencrypted;
-			struct dentry *eapol;
-			struct dentry *ieee8021_x;
 			struct dentry *peer;
 		} wds;
 		struct {
 			struct dentry *channel_use;
 			struct dentry *drop_unencrypted;
-			struct dentry *eapol;
-			struct dentry *ieee8021_x;
 		} vlan;
 		struct {
 			struct dentry *mode;
@@ -387,13 +391,23 @@ struct ieee80211_sub_if_data {
 		struct dentry *default_key;
 	} debugfs;
 #endif
+	/* must be last, dynamically sized area in this! */
+	struct ieee80211_vif vif;
 };
 
+static inline
+struct ieee80211_sub_if_data *vif_to_sdata(struct ieee80211_vif *p)
+{
+	return container_of(p, struct ieee80211_sub_if_data, vif);
+}
+
 #define IEEE80211_DEV_TO_SUB_IF(dev) netdev_priv(dev)
 
 enum {
 	IEEE80211_RX_MSG	= 1,
 	IEEE80211_TX_STATUS_MSG	= 2,
+	IEEE80211_DELBA_MSG	= 3,
+	IEEE80211_ADDBA_MSG	= 4,
 };
 
 struct ieee80211_local {
@@ -404,12 +418,11 @@ struct ieee80211_local {
 
 	const struct ieee80211_ops *ops;
 
-	/* List of registered struct ieee80211_hw_mode */
-	struct list_head modes_list;
-
 	struct net_device *mdev; /* wmaster# - "master" 802.11 device */
 	int open_count;
-	int monitors;
+	int monitors, cooked_mntrs;
+	/* number of interfaces with corresponding FIF_ flags */
+	int fif_fcsfail, fif_plcpfail, fif_control, fif_other_bss;
 	unsigned int filter_flags; /* FIF_* */
 	struct iw_statistics wstats;
 	u8 wstats_flags;
@@ -437,8 +450,8 @@ struct ieee80211_local {
 	struct sta_info *sta_hash[STA_HASH_SIZE];
 	struct timer_list sta_cleanup;
 
-	unsigned long state[NUM_TX_DATA_QUEUES];
-	struct ieee80211_tx_stored_packet pending_packet[NUM_TX_DATA_QUEUES];
+	unsigned long state[NUM_TX_DATA_QUEUES_AMPDU];
+	struct ieee80211_tx_stored_packet pending_packet[NUM_TX_DATA_QUEUES_AMPDU];
 	struct tasklet_struct tx_pending_tasklet;
 
 	/* number of interfaces with corresponding IFF_ flags */
@@ -446,11 +459,6 @@ struct ieee80211_local {
 
 	struct rate_control_ref *rate_ctrl;
 
-	/* Supported and basic rate filters for different modes. These are
-	 * pointers to -1 terminated lists and rates in 100 kbps units. */
-	int *supp_rates[NUM_IEEE80211_MODES];
-	int *basic_rates[NUM_IEEE80211_MODES];
-
 	int rts_threshold;
 	int fragmentation_threshold;
 	int short_retry_limit; /* dot11ShortRetryLimit */
@@ -464,29 +472,23 @@ struct ieee80211_local {
 			     * deliver multicast frames both back to wireless
 			     * media and to the local net stack */
 
-	ieee80211_rx_handler *rx_pre_handlers;
-	ieee80211_rx_handler *rx_handlers;
-	ieee80211_tx_handler *tx_handlers;
-
 	struct list_head interfaces;
 
-	int sta_scanning;
+	bool sta_sw_scanning;
+	bool sta_hw_scanning;
 	int scan_channel_idx;
+	enum ieee80211_band scan_band;
+
 	enum { SCAN_SET_CHANNEL, SCAN_SEND_PROBE } scan_state;
 	unsigned long last_scan_completed;
 	struct delayed_work scan_work;
 	struct net_device *scan_dev;
 	struct ieee80211_channel *oper_channel, *scan_channel;
-	struct ieee80211_hw_mode *oper_hw_mode, *scan_hw_mode;
 	u8 scan_ssid[IEEE80211_MAX_SSID_LEN];
 	size_t scan_ssid_len;
 	struct list_head sta_bss_list;
 	struct ieee80211_sta_bss *sta_bss_hash[STA_HASH_SIZE];
 	spinlock_t sta_bss_lock;
-#define IEEE80211_SCAN_MATCH_SSID BIT(0)
-#define IEEE80211_SCAN_WPA_ONLY BIT(1)
-#define IEEE80211_SCAN_EXTRA_INFO BIT(2)
-	int scan_flags;
 
 	/* SNMP counters */
 	/* dot11CountersTable */
@@ -503,8 +505,9 @@ struct ieee80211_local {
 
 #ifdef CONFIG_MAC80211_LEDS
 	int tx_led_counter, rx_led_counter;
-	struct led_trigger *tx_led, *rx_led, *assoc_led;
-	char tx_led_name[32], rx_led_name[32], assoc_led_name[32];
+	struct led_trigger *tx_led, *rx_led, *assoc_led, *radio_led;
+	char tx_led_name[32], rx_led_name[32],
+	     assoc_led_name[32], radio_led_name[32];
 #endif
 
 	u32 channel_use;
@@ -549,14 +552,8 @@ struct ieee80211_local {
 	int wifi_wme_noack_test;
 	unsigned int wmm_acm; /* bit field of ACM bits (BIT(802.1D tag)) */
 
-	unsigned int enabled_modes; /* bitfield of allowed modes;
-				      * (1 << MODE_*) */
-	unsigned int hw_modes; /* bitfield of supported hardware modes;
-				* (1 << MODE_*) */
-
 #ifdef CONFIG_MAC80211_DEBUGFS
 	struct local_debugfsdentries {
-		struct dentry *channel;
 		struct dentry *frequency;
 		struct dentry *antenna_sel_tx;
 		struct dentry *antenna_sel_rx;
@@ -566,9 +563,7 @@ struct ieee80211_local {
 		struct dentry *short_retry_limit;
 		struct dentry *long_retry_limit;
 		struct dentry *total_ps_buffered;
-		struct dentry *mode;
 		struct dentry *wep_iv;
-		struct dentry *modes;
 		struct dentry *statistics;
 		struct local_debugfsdentries_statsdentries {
 			struct dentry *transmitted_fragment_count;
@@ -616,6 +611,12 @@ struct ieee80211_local {
 #endif
 };
 
+/* this struct represents 802.11n's RA/TID combination */
+struct ieee80211_ra_tid {
+	u8 ra[ETH_ALEN];
+	u16 tid;
+};
+
 static inline struct ieee80211_local *hw_to_local(
 	struct ieee80211_hw *hw)
 {
@@ -673,23 +674,6 @@ static inline void bss_tim_clear(struct ieee80211_local *local,
 	read_unlock_bh(&local->sta_lock);
 }
 
-/**
- * ieee80211_is_erp_rate - Check if a rate is an ERP rate
- * @phymode: The PHY-mode for this rate (MODE_IEEE80211...)
- * @rate: Transmission rate to check, in 100 kbps
- *
- * Check if a given rate is an Extended Rate PHY (ERP) rate.
- */
-static inline int ieee80211_is_erp_rate(int phymode, int rate)
-{
-	if (phymode == MODE_IEEE80211G) {
-		if (rate != 10 && rate != 20 &&
-		    rate != 55 && rate != 110)
-			return 1;
-	}
-	return 0;
-}
-
 static inline int ieee80211_bssid_match(const u8 *raddr, const u8 *addr)
 {
 	return compare_ether_addr(raddr, addr) == 0 ||
@@ -701,13 +685,12 @@ static inline int ieee80211_bssid_match(const u8 *raddr, const u8 *addr)
 int ieee80211_hw_config(struct ieee80211_local *local);
 int ieee80211_if_config(struct net_device *dev);
 int ieee80211_if_config_beacon(struct net_device *dev);
-void ieee80211_prepare_rates(struct ieee80211_local *local,
-			     struct ieee80211_hw_mode *mode);
 void ieee80211_tx_set_iswep(struct ieee80211_txrx_data *tx);
 int ieee80211_if_update_wds(struct net_device *dev, u8 *remote_addr);
 void ieee80211_if_setup(struct net_device *dev);
-struct ieee80211_rate *ieee80211_get_rate(struct ieee80211_local *local,
-					  int phymode, int hwrate);
+int ieee80211_hw_config_ht(struct ieee80211_local *local, int enable_ht,
+			   struct ieee80211_ht_info *req_ht_cap,
+			   struct ieee80211_ht_bss_info *req_bss_cap);
 
 /* ieee80211_ioctl.c */
 extern const struct iw_handler_def ieee80211_iw_handler_def;
@@ -735,7 +718,7 @@ extern const struct iw_handler_def ieee80211_iw_handler_def;
 /* ieee80211_ioctl.c */
 int ieee80211_set_compression(struct ieee80211_local *local,
 			      struct net_device *dev, struct sta_info *sta);
-int ieee80211_set_channel(struct ieee80211_local *local, int channel, int freq);
+int ieee80211_set_freq(struct ieee80211_local *local, int freq);
 /* ieee80211_sta.c */
 void ieee80211_sta_timer(unsigned long data);
 void ieee80211_sta_work(struct work_struct *work);
@@ -749,8 +732,9 @@ int ieee80211_sta_req_scan(struct net_device *dev, u8 *ssid, size_t ssid_len);
 void ieee80211_sta_req_auth(struct net_device *dev,
 			    struct ieee80211_if_sta *ifsta);
 int ieee80211_sta_scan_results(struct net_device *dev, char *buf, size_t len);
-void ieee80211_sta_rx_scan(struct net_device *dev, struct sk_buff *skb,
-			   struct ieee80211_rx_status *rx_status);
+ieee80211_rx_result ieee80211_sta_rx_scan(
+	struct net_device *dev, struct sk_buff *skb,
+	struct ieee80211_rx_status *rx_status);
 void ieee80211_rx_bss_list_init(struct net_device *dev);
 void ieee80211_rx_bss_list_deinit(struct net_device *dev);
 int ieee80211_sta_set_extra_ie(struct net_device *dev, char *ie, size_t len);
@@ -759,9 +743,23 @@ struct sta_info * ieee80211_ibss_add_sta(struct net_device *dev,
 					 u8 *addr);
 int ieee80211_sta_deauthenticate(struct net_device *dev, u16 reason);
 int ieee80211_sta_disassociate(struct net_device *dev, u16 reason);
-void ieee80211_erp_info_change_notify(struct net_device *dev, u8 changes);
+void ieee80211_bss_info_change_notify(struct ieee80211_sub_if_data *sdata,
+				      u32 changed);
 void ieee80211_reset_erp_info(struct net_device *dev);
-
+int ieee80211_ht_cap_ie_to_ht_info(struct ieee80211_ht_cap *ht_cap_ie,
+				   struct ieee80211_ht_info *ht_info);
+int ieee80211_ht_addt_info_ie_to_ht_bss_info(
+			struct ieee80211_ht_addt_info *ht_add_info_ie,
+			struct ieee80211_ht_bss_info *bss_info);
+void ieee80211_send_addba_request(struct net_device *dev, const u8 *da,
+				  u16 tid, u8 dialog_token, u16 start_seq_num,
+				  u16 agg_size, u16 timeout);
+void ieee80211_send_delba(struct net_device *dev, const u8 *da, u16 tid,
+				u16 initiator, u16 reason_code);
+void ieee80211_sta_stop_rx_ba_session(struct net_device *dev, u8 *da,
+				u16 tid, u16 initiator, u16 reason);
+void sta_rx_agg_session_timer_expired(unsigned long data);
+void sta_addba_resp_timer_expired(unsigned long data);
 /* ieee80211_iface.c */
 int ieee80211_if_add(struct net_device *dev, const char *name,
 		     struct net_device **new_dev, int type);
@@ -773,16 +771,7 @@ int ieee80211_if_remove(struct net_device *dev, const char *name, int id);
 void ieee80211_if_free(struct net_device *dev);
 void ieee80211_if_sdata_init(struct ieee80211_sub_if_data *sdata);
 
-/* regdomain.c */
-void ieee80211_regdomain_init(void);
-void ieee80211_set_default_regdomain(struct ieee80211_hw_mode *mode);
-
-/* rx handling */
-extern ieee80211_rx_handler ieee80211_rx_pre_handlers[];
-extern ieee80211_rx_handler ieee80211_rx_handlers[];
-
 /* tx handling */
-extern ieee80211_tx_handler ieee80211_tx_handlers[];
 void ieee80211_clear_tx_pending(struct ieee80211_local *local);
 void ieee80211_tx_pending(unsigned long data);
 int ieee80211_master_start_xmit(struct sk_buff *skb, struct net_device *dev);
@@ -793,8 +782,8 @@ int ieee80211_subif_start_xmit(struct sk_buff *skb, struct net_device *dev);
 extern void *mac80211_wiphy_privid; /* for wiphy privid */
 extern const unsigned char rfc1042_header[6];
 extern const unsigned char bridge_tunnel_header[6];
-u8 *ieee80211_get_bssid(struct ieee80211_hdr *hdr, size_t len);
-int ieee80211_is_eapol(const struct sk_buff *skb);
+u8 *ieee80211_get_bssid(struct ieee80211_hdr *hdr, size_t len,
+			enum ieee80211_if_types type);
 int ieee80211_frame_duration(struct ieee80211_local *local, size_t len,
 			     int rate, int erp, int short_preamble);
 void mac80211_ev_michael_mic_failure(struct net_device *dev, int keyidx,
diff --git a/package/mac80211/src/net/mac80211/ieee80211_iface.c b/package/mac80211/src/net/mac80211/ieee80211_iface.c
index 43e505d294..f66f1ddc3f 100644
--- a/package/mac80211/src/net/mac80211/ieee80211_iface.c
+++ b/package/mac80211/src/net/mac80211/ieee80211_iface.c
@@ -22,7 +22,6 @@ void ieee80211_if_sdata_init(struct ieee80211_sub_if_data *sdata)
 
 	/* Default values for sub-interface parameters */
 	sdata->drop_unencrypted = 0;
-	sdata->eapol = 1;
 	for (i = 0; i < IEEE80211_FRAGMENT_MAX; i++)
 		skb_queue_head_init(&sdata->fragments[i].skb_list);
 
@@ -48,7 +47,7 @@ int ieee80211_if_add(struct net_device *dev, const char *name,
 	int ret;
 
 	ASSERT_RTNL();
-	ndev = alloc_netdev(sizeof(struct ieee80211_sub_if_data),
+	ndev = alloc_netdev(sizeof(*sdata) + local->hw.vif_data_size,
 			    name, ieee80211_if_setup);
 	if (!ndev)
 		return -ENOMEM;
@@ -67,7 +66,7 @@ int ieee80211_if_add(struct net_device *dev, const char *name,
 	sdata = IEEE80211_DEV_TO_SUB_IF(ndev);
 	ndev->ieee80211_ptr = &sdata->wdev;
 	sdata->wdev.wiphy = local->hw.wiphy;
-	sdata->type = IEEE80211_IF_TYPE_AP;
+	sdata->vif.type = IEEE80211_IF_TYPE_AP;
 	sdata->dev = ndev;
 	sdata->local = local;
 	ieee80211_if_sdata_init(sdata);
@@ -99,7 +98,7 @@ fail:
 void ieee80211_if_set_type(struct net_device *dev, int type)
 {
 	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-	int oldtype = sdata->type;
+	int oldtype = sdata->vif.type;
 
 	/*
 	 * We need to call this function on the master interface
@@ -117,7 +116,9 @@ void ieee80211_if_set_type(struct net_device *dev, int type)
 
 	/* most have no BSS pointer */
 	sdata->bss = NULL;
-	sdata->type = type;
+	sdata->vif.type = type;
+
+	sdata->basic_rates = 0;
 
 	switch (type) {
 	case IEEE80211_IF_TYPE_WDS:
@@ -127,7 +128,6 @@ void ieee80211_if_set_type(struct net_device *dev, int type)
 		sdata->u.vlan.ap = NULL;
 		break;
 	case IEEE80211_IF_TYPE_AP:
-		sdata->u.ap.dtim_period = 2;
 		sdata->u.ap.force_unicast_rateidx = -1;
 		sdata->u.ap.max_ratectrl_rateidx = -1;
 		skb_queue_head_init(&sdata->u.ap.ps_bc_buf);
@@ -160,6 +160,8 @@ void ieee80211_if_set_type(struct net_device *dev, int type)
 	case IEEE80211_IF_TYPE_MNTR:
 		dev->type = ARPHRD_IEEE80211_RADIOTAP;
 		dev->hard_start_xmit = ieee80211_monitor_start_xmit;
+		sdata->u.mntr_flags = MONITOR_FLAG_CONTROL |
+				      MONITOR_FLAG_OTHER_BSS;
 		break;
 	default:
 		printk(KERN_WARNING "%s: %s: Unknown interface type 0x%x",
@@ -182,7 +184,7 @@ void ieee80211_if_reinit(struct net_device *dev)
 
 	ieee80211_if_sdata_deinit(sdata);
 
-	switch (sdata->type) {
+	switch (sdata->vif.type) {
 	case IEEE80211_IF_TYPE_INVALID:
 		/* cannot happen */
 		WARN_ON(1);
@@ -208,8 +210,7 @@ void ieee80211_if_reinit(struct net_device *dev)
 			}
 		}
 
-		kfree(sdata->u.ap.beacon_head);
-		kfree(sdata->u.ap.beacon_tail);
+		kfree(sdata->u.ap.beacon);
 
 		while ((skb = skb_dequeue(&sdata->u.ap.ps_bc_buf))) {
 			local->total_ps_buffered--;
@@ -280,7 +281,7 @@ int ieee80211_if_remove(struct net_device *dev, const char *name, int id)
 	ASSERT_RTNL();
 
 	list_for_each_entry_safe(sdata, n, &local->interfaces, list) {
-		if ((sdata->type == id || id == -1) &&
+		if ((sdata->vif.type == id || id == -1) &&
 		    strcmp(name, sdata->dev->name) == 0 &&
 		    sdata->dev != local->mdev) {
 			list_del_rcu(&sdata->list);
diff --git a/package/mac80211/src/net/mac80211/ieee80211_ioctl.c b/package/mac80211/src/net/mac80211/ieee80211_ioctl.c
index f95d488726..54ad07aafe 100644
--- a/package/mac80211/src/net/mac80211/ieee80211_ioctl.c
+++ b/package/mac80211/src/net/mac80211/ieee80211_ioctl.c
@@ -21,6 +21,7 @@
 
 #include <net/mac80211.h>
 #include "ieee80211_i.h"
+#include "ieee80211_led.h"
 #include "ieee80211_rate.h"
 #include "wpa.h"
 #include "aes_ccm.h"
@@ -64,9 +65,10 @@ static int ieee80211_set_encryption(struct net_device *dev, u8 *sta_addr,
 		sta = sta_info_get(local, sta_addr);
 		if (!sta) {
 #ifdef CONFIG_MAC80211_VERBOSE_DEBUG
+			DECLARE_MAC_BUF(mac);
 			printk(KERN_DEBUG "%s: set_encrypt - unknown addr "
-			       MAC_FMT "\n",
-			       dev->name, MAC_ARG(sta_addr));
+			       "%s\n",
+			       dev->name, print_mac(mac, sta_addr));
 #endif /* CONFIG_MAC80211_VERBOSE_DEBUG */
 
 			return -ENOENT;
@@ -110,8 +112,8 @@ static int ieee80211_ioctl_siwgenie(struct net_device *dev,
 	if (sdata->flags & IEEE80211_SDATA_USERSPACE_MLME)
 		return -EOPNOTSUPP;
 
-	if (sdata->type == IEEE80211_IF_TYPE_STA ||
-	    sdata->type == IEEE80211_IF_TYPE_IBSS) {
+	if (sdata->vif.type == IEEE80211_IF_TYPE_STA ||
+	    sdata->vif.type == IEEE80211_IF_TYPE_IBSS) {
 		int ret = ieee80211_sta_set_extra_ie(dev, extra, data->length);
 		if (ret)
 			return ret;
@@ -127,22 +129,7 @@ static int ieee80211_ioctl_giwname(struct net_device *dev,
 				   struct iw_request_info *info,
 				   char *name, char *extra)
 {
-	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
-
-	switch (local->hw.conf.phymode) {
-	case MODE_IEEE80211A:
-		strcpy(name, "IEEE 802.11a");
-		break;
-	case MODE_IEEE80211B:
-		strcpy(name, "IEEE 802.11b");
-		break;
-	case MODE_IEEE80211G:
-		strcpy(name, "IEEE 802.11g");
-		break;
-	default:
-		strcpy(name, "IEEE 802.11");
-		break;
-	}
+	strcpy(name, "IEEE 802.11");
 
 	return 0;
 }
@@ -154,7 +141,7 @@ static int ieee80211_ioctl_giwrange(struct net_device *dev,
 {
 	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
 	struct iw_range *range = (struct iw_range *) extra;
-	struct ieee80211_hw_mode *mode = NULL;
+	enum ieee80211_band band;
 	int c = 0;
 
 	data->length = sizeof(struct iw_range);
@@ -189,24 +176,27 @@ static int ieee80211_ioctl_giwrange(struct net_device *dev,
 	range->enc_capa = IW_ENC_CAPA_WPA | IW_ENC_CAPA_WPA2 |
 			  IW_ENC_CAPA_CIPHER_TKIP | IW_ENC_CAPA_CIPHER_CCMP;
 
-	list_for_each_entry(mode, &local->modes_list, list) {
-		int i = 0;
 
-		if (!(local->enabled_modes & (1 << mode->mode)) ||
-		    (local->hw_modes & local->enabled_modes &
-		     (1 << MODE_IEEE80211G) && mode->mode == MODE_IEEE80211B))
+	for (band = 0; band < IEEE80211_NUM_BANDS; band ++) {
+		int i;
+		struct ieee80211_supported_band *sband;
+
+		sband = local->hw.wiphy->bands[band];
+
+		if (!sband)
 			continue;
 
-		while (i < mode->num_channels && c < IW_MAX_FREQUENCIES) {
-			struct ieee80211_channel *chan = &mode->channels[i];
+		for (i = 0; i < sband->n_channels && c < IW_MAX_FREQUENCIES; i++) {
+			struct ieee80211_channel *chan = &sband->channels[i];
 
-			if (chan->flag & IEEE80211_CHAN_W_SCAN) {
-				range->freq[c].i = chan->chan;
-				range->freq[c].m = chan->freq * 100000;
-				range->freq[c].e = 1;
+			if (!(chan->flags & IEEE80211_CHAN_DISABLED)) {
+				range->freq[c].i =
+					ieee80211_frequency_to_channel(
+						chan->center_freq);
+				range->freq[c].m = chan->center_freq;
+				range->freq[c].e = 6;
 				c++;
 			}
-			i++;
 		}
 	}
 	range->num_channels = c;
@@ -217,6 +207,8 @@ static int ieee80211_ioctl_giwrange(struct net_device *dev,
 	IW_EVENT_CAPA_SET(range->event_capa, SIOCGIWAP);
 	IW_EVENT_CAPA_SET(range->event_capa, SIOCGIWSCAN);
 
+	range->scan_capa |= IW_SCAN_CAPA_ESSID;
+
 	return 0;
 }
 
@@ -228,7 +220,7 @@ static int ieee80211_ioctl_siwmode(struct net_device *dev,
 	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
 	int type;
 
-	if (sdata->type == IEEE80211_IF_TYPE_VLAN)
+	if (sdata->vif.type == IEEE80211_IF_TYPE_VLAN)
 		return -EOPNOTSUPP;
 
 	switch (*mode) {
@@ -245,7 +237,7 @@ static int ieee80211_ioctl_siwmode(struct net_device *dev,
 		return -EINVAL;
 	}
 
-	if (type == sdata->type)
+	if (type == sdata->vif.type)
 		return 0;
 	if (netif_running(dev))
 		return -EBUSY;
@@ -264,7 +256,7 @@ static int ieee80211_ioctl_giwmode(struct net_device *dev,
 	struct ieee80211_sub_if_data *sdata;
 
 	sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-	switch (sdata->type) {
+	switch (sdata->vif.type) {
 	case IEEE80211_IF_TYPE_AP:
 		*mode = IW_MODE_MASTER;
 		break;
@@ -290,28 +282,38 @@ static int ieee80211_ioctl_giwmode(struct net_device *dev,
 	return 0;
 }
 
-int ieee80211_set_channel(struct ieee80211_local *local, int channel, int freq)
+int ieee80211_set_freq(struct ieee80211_local *local, int freqMHz)
 {
-	struct ieee80211_hw_mode *mode;
-	int c, set = 0;
+	int set = 0;
 	int ret = -EINVAL;
+	enum ieee80211_band band;
+	struct ieee80211_supported_band *sband;
+	int i;
 
-	list_for_each_entry(mode, &local->modes_list, list) {
-		if (!(local->enabled_modes & (1 << mode->mode)))
+	for (band = 0; band < IEEE80211_NUM_BANDS; band ++) {
+		sband = local->hw.wiphy->bands[band];
+
+		if (!sband)
 			continue;
-		for (c = 0; c < mode->num_channels; c++) {
-			struct ieee80211_channel *chan = &mode->channels[c];
-			if (chan->flag & IEEE80211_CHAN_W_SCAN &&
-			    ((chan->chan == channel) || (chan->freq == freq))) {
+
+		for (i = 0; i < sband->n_channels; i++) {
+			struct ieee80211_channel *chan = &sband->channels[i];
+
+			if (chan->flags & IEEE80211_CHAN_DISABLED)
+				continue;
+
+			if (chan->center_freq == freqMHz) {
+				set = 1;
 				local->oper_channel = chan;
-				local->oper_hw_mode = mode;
-				set++;
+				break;
 			}
 		}
+		if (set)
+			break;
 	}
 
 	if (set) {
-		if (local->sta_scanning)
+		if (local->sta_sw_scanning)
 			ret = 0;
 		else
 			ret = ieee80211_hw_config(local);
@@ -329,24 +331,25 @@ static int ieee80211_ioctl_siwfreq(struct net_device *dev,
 	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
 	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
 
-	if (sdata->type == IEEE80211_IF_TYPE_STA)
+	if (sdata->vif.type == IEEE80211_IF_TYPE_STA)
 		sdata->u.sta.flags &= ~IEEE80211_STA_AUTO_CHANNEL_SEL;
 
 	/* freq->e == 0: freq->m = channel; otherwise freq = m * 10^e */
 	if (freq->e == 0) {
 		if (freq->m < 0) {
-			if (sdata->type == IEEE80211_IF_TYPE_STA)
+			if (sdata->vif.type == IEEE80211_IF_TYPE_STA)
 				sdata->u.sta.flags |=
 					IEEE80211_STA_AUTO_CHANNEL_SEL;
 			return 0;
 		} else
-			return ieee80211_set_channel(local, freq->m, -1);
+			return ieee80211_set_freq(local,
+				ieee80211_channel_to_frequency(freq->m));
 	} else {
 		int i, div = 1000000;
 		for (i = 0; i < freq->e; i++)
 			div /= 10;
 		if (div > 0)
-			return ieee80211_set_channel(local, -1, freq->m / div);
+			return ieee80211_set_freq(local, freq->m / div);
 		else
 			return -EINVAL;
 	}
@@ -359,10 +362,7 @@ static int ieee80211_ioctl_giwfreq(struct net_device *dev,
 {
 	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
 
-	/* TODO: in station mode (Managed/Ad-hoc) might need to poll low-level
-	 * driver for the current channel with firmware-based management */
-
-	freq->m = local->hw.conf.freq;
+	freq->m = local->hw.conf.channel->center_freq;
 	freq->e = 6;
 
 	return 0;
@@ -381,8 +381,8 @@ static int ieee80211_ioctl_siwessid(struct net_device *dev,
 		len--;
 
 	sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-	if (sdata->type == IEEE80211_IF_TYPE_STA ||
-	    sdata->type == IEEE80211_IF_TYPE_IBSS) {
+	if (sdata->vif.type == IEEE80211_IF_TYPE_STA ||
+	    sdata->vif.type == IEEE80211_IF_TYPE_IBSS) {
 		int ret;
 		if (sdata->flags & IEEE80211_SDATA_USERSPACE_MLME) {
 			if (len > IEEE80211_MAX_SSID_LEN)
@@ -402,7 +402,7 @@ static int ieee80211_ioctl_siwessid(struct net_device *dev,
 		return 0;
 	}
 
-	if (sdata->type == IEEE80211_IF_TYPE_AP) {
+	if (sdata->vif.type == IEEE80211_IF_TYPE_AP) {
 		memcpy(sdata->u.ap.ssid, ssid, len);
 		memset(sdata->u.ap.ssid + len, 0,
 		       IEEE80211_MAX_SSID_LEN - len);
@@ -421,8 +421,8 @@ static int ieee80211_ioctl_giwessid(struct net_device *dev,
 
 	struct ieee80211_sub_if_data *sdata;
 	sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-	if (sdata->type == IEEE80211_IF_TYPE_STA ||
-	    sdata->type == IEEE80211_IF_TYPE_IBSS) {
+	if (sdata->vif.type == IEEE80211_IF_TYPE_STA ||
+	    sdata->vif.type == IEEE80211_IF_TYPE_IBSS) {
 		int res = ieee80211_sta_get_ssid(dev, ssid, &len);
 		if (res == 0) {
 			data->length = len;
@@ -432,7 +432,7 @@ static int ieee80211_ioctl_giwessid(struct net_device *dev,
 		return res;
 	}
 
-	if (sdata->type == IEEE80211_IF_TYPE_AP) {
+	if (sdata->vif.type == IEEE80211_IF_TYPE_AP) {
 		len = sdata->u.ap.ssid_len;
 		if (len > IW_ESSID_MAX_SIZE)
 			len = IW_ESSID_MAX_SIZE;
@@ -452,8 +452,8 @@ static int ieee80211_ioctl_siwap(struct net_device *dev,
 	struct ieee80211_sub_if_data *sdata;
 
 	sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-	if (sdata->type == IEEE80211_IF_TYPE_STA ||
-	    sdata->type == IEEE80211_IF_TYPE_IBSS) {
+	if (sdata->vif.type == IEEE80211_IF_TYPE_STA ||
+	    sdata->vif.type == IEEE80211_IF_TYPE_IBSS) {
 		int ret;
 		if (sdata->flags & IEEE80211_SDATA_USERSPACE_MLME) {
 			memcpy(sdata->u.sta.bssid, (u8 *) &ap_addr->sa_data,
@@ -472,7 +472,7 @@ static int ieee80211_ioctl_siwap(struct net_device *dev,
 			return ret;
 		ieee80211_sta_req_auth(dev, &sdata->u.sta);
 		return 0;
-	} else if (sdata->type == IEEE80211_IF_TYPE_WDS) {
+	} else if (sdata->vif.type == IEEE80211_IF_TYPE_WDS) {
 		if (memcmp(sdata->u.wds.remote_addr, (u8 *) &ap_addr->sa_data,
 			   ETH_ALEN) == 0)
 			return 0;
@@ -490,12 +490,12 @@ static int ieee80211_ioctl_giwap(struct net_device *dev,
 	struct ieee80211_sub_if_data *sdata;
 
 	sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-	if (sdata->type == IEEE80211_IF_TYPE_STA ||
-	    sdata->type == IEEE80211_IF_TYPE_IBSS) {
+	if (sdata->vif.type == IEEE80211_IF_TYPE_STA ||
+	    sdata->vif.type == IEEE80211_IF_TYPE_IBSS) {
 		ap_addr->sa_family = ARPHRD_ETHER;
 		memcpy(&ap_addr->sa_data, sdata->u.sta.bssid, ETH_ALEN);
 		return 0;
-	} else if (sdata->type == IEEE80211_IF_TYPE_WDS) {
+	} else if (sdata->vif.type == IEEE80211_IF_TYPE_WDS) {
 		ap_addr->sa_family = ARPHRD_ETHER;
 		memcpy(&ap_addr->sa_data, sdata->u.wds.remote_addr, ETH_ALEN);
 		return 0;
@@ -507,32 +507,27 @@ static int ieee80211_ioctl_giwap(struct net_device *dev,
 
 static int ieee80211_ioctl_siwscan(struct net_device *dev,
 				   struct iw_request_info *info,
-				   struct iw_point *data, char *extra)
+				   union iwreq_data *wrqu, char *extra)
 {
-	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
 	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+	struct iw_scan_req *req = NULL;
 	u8 *ssid = NULL;
 	size_t ssid_len = 0;
 
 	if (!netif_running(dev))
 		return -ENETDOWN;
 
-	switch (sdata->type) {
-	case IEEE80211_IF_TYPE_STA:
-	case IEEE80211_IF_TYPE_IBSS:
-		if (local->scan_flags & IEEE80211_SCAN_MATCH_SSID) {
-			ssid = sdata->u.sta.ssid;
-			ssid_len = sdata->u.sta.ssid_len;
-		}
-		break;
-	case IEEE80211_IF_TYPE_AP:
-		if (local->scan_flags & IEEE80211_SCAN_MATCH_SSID) {
-			ssid = sdata->u.ap.ssid;
-			ssid_len = sdata->u.ap.ssid_len;
-		}
-		break;
-	default:
+	if (sdata->vif.type != IEEE80211_IF_TYPE_STA &&
+	    sdata->vif.type != IEEE80211_IF_TYPE_IBSS &&
+	    sdata->vif.type != IEEE80211_IF_TYPE_AP)
 		return -EOPNOTSUPP;
+
+	/* if SSID was specified explicitly then use that */
+	if (wrqu->data.length == sizeof(struct iw_scan_req) &&
+	    wrqu->data.flags & IW_SCAN_THIS_ESSID) {
+		req = (struct iw_scan_req *)extra;
+		ssid = req->essid;
+		ssid_len = req->essid_len;
 	}
 
 	return ieee80211_sta_req_scan(dev, ssid, ssid_len);
@@ -545,8 +540,10 @@ static int ieee80211_ioctl_giwscan(struct net_device *dev,
 {
 	int res;
 	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
-	if (local->sta_scanning)
+
+	if (local->sta_sw_scanning || local->sta_hw_scanning)
 		return -EAGAIN;
+
 	res = ieee80211_sta_scan_results(dev, extra, data->length);
 	if (res >= 0) {
 		data->length = res;
@@ -562,15 +559,17 @@ static int ieee80211_ioctl_siwrate(struct net_device *dev,
 				  struct iw_param *rate, char *extra)
 {
 	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
-	struct ieee80211_hw_mode *mode;
-	int i;
+	int i, err = -EINVAL;
 	u32 target_rate = rate->value / 100000;
 	struct ieee80211_sub_if_data *sdata;
+	struct ieee80211_supported_band *sband;
 
 	sdata = IEEE80211_DEV_TO_SUB_IF(dev);
 	if (!sdata->bss)
 		return -ENODEV;
-	mode = local->oper_hw_mode;
+
+	sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
+
 	/* target_rate = -1, rate->fixed = 0 means auto only, so use all rates
 	 * target_rate = X, rate->fixed = 1 means only rate X
 	 * target_rate = X, rate->fixed = 0 means all rates <= X */
@@ -578,18 +577,20 @@ static int ieee80211_ioctl_siwrate(struct net_device *dev,
 	sdata->bss->force_unicast_rateidx = -1;
 	if (rate->value < 0)
 		return 0;
-	for (i=0; i< mode->num_rates; i++) {
-		struct ieee80211_rate *rates = &mode->rates[i];
-		int this_rate = rates->rate;
+
+	for (i=0; i< sband->n_bitrates; i++) {
+		struct ieee80211_rate *brate = &sband->bitrates[i];
+		int this_rate = brate->bitrate;
 
 		if (target_rate == this_rate) {
 			sdata->bss->max_ratectrl_rateidx = i;
 			if (rate->fixed)
 				sdata->bss->force_unicast_rateidx = i;
+			err = 0;
 			break;
 		}
 	}
-	return 0;
+	return err;
 }
 
 static int ieee80211_ioctl_giwrate(struct net_device *dev,
@@ -599,18 +600,24 @@ static int ieee80211_ioctl_giwrate(struct net_device *dev,
 	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
 	struct sta_info *sta;
 	struct ieee80211_sub_if_data *sdata;
+	struct ieee80211_supported_band *sband;
 
 	sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-	if (sdata->type == IEEE80211_IF_TYPE_STA)
+
+	if (sdata->vif.type == IEEE80211_IF_TYPE_STA)
 		sta = sta_info_get(local, sdata->u.sta.bssid);
 	else
 		return -EOPNOTSUPP;
 	if (!sta)
 		return -ENODEV;
-	if (sta->txrate < local->oper_hw_mode->num_rates)
-		rate->value = local->oper_hw_mode->rates[sta->txrate].rate * 100000;
+
+	sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
+
+	if (sta->txrate_idx < sband->n_bitrates)
+		rate->value = sband->bitrates[sta->txrate_idx].bitrate;
 	else
 		rate->value = 0;
+	rate->value *= 100000;
 	sta_info_put(sta);
 	return 0;
 }
@@ -621,22 +628,38 @@ static int ieee80211_ioctl_siwtxpower(struct net_device *dev,
 {
 	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
 	bool need_reconfig = 0;
+	int new_power_level;
 
 	if ((data->txpower.flags & IW_TXPOW_TYPE) != IW_TXPOW_DBM)
 		return -EINVAL;
 	if (data->txpower.flags & IW_TXPOW_RANGE)
 		return -EINVAL;
-	if (!data->txpower.fixed)
-		return -EINVAL;
 
-	if (local->hw.conf.power_level != data->txpower.value) {
-		local->hw.conf.power_level = data->txpower.value;
+	if (data->txpower.fixed) {
+		new_power_level = data->txpower.value;
+	} else {
+		/*
+		 * Automatic power level. Use maximum power for the current
+		 * channel. Should be part of rate control.
+		 */
+		struct ieee80211_channel* chan = local->hw.conf.channel;
+		if (!chan)
+			return -EINVAL;
+
+		new_power_level = chan->max_power;
+	}
+
+	if (local->hw.conf.power_level != new_power_level) {
+		local->hw.conf.power_level = new_power_level;
 		need_reconfig = 1;
 	}
+
 	if (local->hw.conf.radio_enabled != !(data->txpower.disabled)) {
 		local->hw.conf.radio_enabled = !(data->txpower.disabled);
 		need_reconfig = 1;
+		ieee80211_led_radio(local, local->hw.conf.radio_enabled);
 	}
+
 	if (need_reconfig) {
 		ieee80211_hw_config(local);
 		/* The return value of hw_config is not of big interest here,
@@ -801,8 +824,8 @@ static int ieee80211_ioctl_siwmlme(struct net_device *dev,
 	struct iw_mlme *mlme = (struct iw_mlme *) extra;
 
 	sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-	if (sdata->type != IEEE80211_IF_TYPE_STA &&
-	    sdata->type != IEEE80211_IF_TYPE_IBSS)
+	if (sdata->vif.type != IEEE80211_IF_TYPE_STA &&
+	    sdata->vif.type != IEEE80211_IF_TYPE_IBSS)
 		return -EINVAL;
 
 	switch (mlme->cmd) {
@@ -904,7 +927,6 @@ static int ieee80211_ioctl_siwauth(struct net_device *dev,
 				   struct iw_request_info *info,
 				   struct iw_param *data, char *extra)
 {
-	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
 	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
 	int ret = 0;
 
@@ -914,32 +936,33 @@ static int ieee80211_ioctl_siwauth(struct net_device *dev,
 	case IW_AUTH_CIPHER_GROUP:
 	case IW_AUTH_WPA_ENABLED:
 	case IW_AUTH_RX_UNENCRYPTED_EAPOL:
-		break;
 	case IW_AUTH_KEY_MGMT:
-		if (sdata->type != IEEE80211_IF_TYPE_STA)
+		break;
+	case IW_AUTH_DROP_UNENCRYPTED:
+		sdata->drop_unencrypted = !!data->value;
+		break;
+	case IW_AUTH_PRIVACY_INVOKED:
+		if (sdata->vif.type != IEEE80211_IF_TYPE_STA)
 			ret = -EINVAL;
 		else {
+			sdata->u.sta.flags &= ~IEEE80211_STA_PRIVACY_INVOKED;
 			/*
-			 * Key management was set by wpa_supplicant,
-			 * we only need this to associate to a network
-			 * that has privacy enabled regardless of not
-			 * having a key.
+			 * Privacy invoked by wpa_supplicant, store the
+			 * value and allow associating to a protected
+			 * network without having a key up front.
 			 */
-			sdata->u.sta.key_management_enabled = !!data->value;
+			if (data->value)
+				sdata->u.sta.flags |=
+					IEEE80211_STA_PRIVACY_INVOKED;
 		}
 		break;
 	case IW_AUTH_80211_AUTH_ALG:
-		if (sdata->type == IEEE80211_IF_TYPE_STA ||
-		    sdata->type == IEEE80211_IF_TYPE_IBSS)
+		if (sdata->vif.type == IEEE80211_IF_TYPE_STA ||
+		    sdata->vif.type == IEEE80211_IF_TYPE_IBSS)
 			sdata->u.sta.auth_algs = data->value;
 		else
 			ret = -EOPNOTSUPP;
 		break;
-	case IW_AUTH_PRIVACY_INVOKED:
-		if (local->ops->set_privacy_invoked)
-			ret = local->ops->set_privacy_invoked(
-					local_to_hw(local), data->value);
-		break;
 	default:
 		ret = -EOPNOTSUPP;
 		break;
@@ -955,8 +978,8 @@ static struct iw_statistics *ieee80211_get_wireless_stats(struct net_device *dev
 	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
 	struct sta_info *sta = NULL;
 
-	if (sdata->type == IEEE80211_IF_TYPE_STA ||
-	    sdata->type == IEEE80211_IF_TYPE_IBSS)
+	if (sdata->vif.type == IEEE80211_IF_TYPE_STA ||
+	    sdata->vif.type == IEEE80211_IF_TYPE_IBSS)
 		sta = sta_info_get(local, sdata->u.sta.bssid);
 	if (!sta) {
 		wstats->discard.fragment = 0;
@@ -984,8 +1007,8 @@ static int ieee80211_ioctl_giwauth(struct net_device *dev,
 
 	switch (data->flags & IW_AUTH_INDEX) {
 	case IW_AUTH_80211_AUTH_ALG:
-		if (sdata->type == IEEE80211_IF_TYPE_STA ||
-		    sdata->type == IEEE80211_IF_TYPE_IBSS)
+		if (sdata->vif.type == IEEE80211_IF_TYPE_STA ||
+		    sdata->vif.type == IEEE80211_IF_TYPE_IBSS)
 			data->value = sdata->u.sta.auth_algs;
 		else
 			ret = -EOPNOTSUPP;
diff --git a/package/mac80211/src/net/mac80211/ieee80211_led.c b/package/mac80211/src/net/mac80211/ieee80211_led.c
index 4cf89af9d1..f401484ab6 100644
--- a/package/mac80211/src/net/mac80211/ieee80211_led.c
+++ b/package/mac80211/src/net/mac80211/ieee80211_led.c
@@ -43,6 +43,16 @@ void ieee80211_led_assoc(struct ieee80211_local *local, bool associated)
 		led_trigger_event(local->assoc_led, LED_OFF);
 }
 
+void ieee80211_led_radio(struct ieee80211_local *local, bool enabled)
+{
+	if (unlikely(!local->radio_led))
+		return;
+	if (enabled)
+		led_trigger_event(local->radio_led, LED_FULL);
+	else
+		led_trigger_event(local->radio_led, LED_OFF);
+}
+
 void ieee80211_led_init(struct ieee80211_local *local)
 {
 	local->rx_led = kzalloc(sizeof(struct led_trigger), GFP_KERNEL);
@@ -77,10 +87,25 @@ void ieee80211_led_init(struct ieee80211_local *local)
 			local->assoc_led = NULL;
 		}
 	}
+
+	local->radio_led = kzalloc(sizeof(struct led_trigger), GFP_KERNEL);
+	if (local->radio_led) {
+		snprintf(local->radio_led_name, sizeof(local->radio_led_name),
+			 "%sradio", wiphy_name(local->hw.wiphy));
+		local->radio_led->name = local->radio_led_name;
+		if (led_trigger_register(local->radio_led)) {
+			kfree(local->radio_led);
+			local->radio_led = NULL;
+		}
+	}
 }
 
 void ieee80211_led_exit(struct ieee80211_local *local)
 {
+	if (local->radio_led) {
+		led_trigger_unregister(local->radio_led);
+		kfree(local->radio_led);
+	}
 	if (local->assoc_led) {
 		led_trigger_unregister(local->assoc_led);
 		kfree(local->assoc_led);
@@ -95,6 +120,16 @@ void ieee80211_led_exit(struct ieee80211_local *local)
 	}
 }
 
+char *__ieee80211_get_radio_led_name(struct ieee80211_hw *hw)
+{
+	struct ieee80211_local *local = hw_to_local(hw);
+
+	if (local->radio_led)
+		return local->radio_led_name;
+	return NULL;
+}
+EXPORT_SYMBOL(__ieee80211_get_radio_led_name);
+
 char *__ieee80211_get_assoc_led_name(struct ieee80211_hw *hw)
 {
 	struct ieee80211_local *local = hw_to_local(hw);
diff --git a/package/mac80211/src/net/mac80211/ieee80211_led.h b/package/mac80211/src/net/mac80211/ieee80211_led.h
index 0feb226198..77b1e1ba60 100644
--- a/package/mac80211/src/net/mac80211/ieee80211_led.h
+++ b/package/mac80211/src/net/mac80211/ieee80211_led.h
@@ -16,6 +16,8 @@ extern void ieee80211_led_rx(struct ieee80211_local *local);
 extern void ieee80211_led_tx(struct ieee80211_local *local, int q);
 extern void ieee80211_led_assoc(struct ieee80211_local *local,
 				bool associated);
+extern void ieee80211_led_radio(struct ieee80211_local *local,
+				bool enabled);
 extern void ieee80211_led_init(struct ieee80211_local *local);
 extern void ieee80211_led_exit(struct ieee80211_local *local);
 #else
@@ -29,6 +31,10 @@ static inline void ieee80211_led_assoc(struct ieee80211_local *local,
 				       bool associated)
 {
 }
+static inline void ieee80211_led_radio(struct ieee80211_local *local,
+				       bool enabled)
+{
+}
 static inline void ieee80211_led_init(struct ieee80211_local *local)
 {
 }
diff --git a/package/mac80211/src/net/mac80211/ieee80211_rate.c b/package/mac80211/src/net/mac80211/ieee80211_rate.c
index 93abb8fff1..ebe29b716b 100644
--- a/package/mac80211/src/net/mac80211/ieee80211_rate.c
+++ b/package/mac80211/src/net/mac80211/ieee80211_rate.c
@@ -21,17 +21,35 @@ struct rate_control_alg {
 static LIST_HEAD(rate_ctrl_algs);
 static DEFINE_MUTEX(rate_ctrl_mutex);
 
+static char *ieee80211_default_rc_algo = CONFIG_MAC80211_RC_DEFAULT;
+module_param(ieee80211_default_rc_algo, charp, 0644);
+MODULE_PARM_DESC(ieee80211_default_rc_algo,
+		 "Default rate control algorithm for mac80211 to use");
+
 int ieee80211_rate_control_register(struct rate_control_ops *ops)
 {
 	struct rate_control_alg *alg;
 
+	if (!ops->name)
+		return -EINVAL;
+
+	mutex_lock(&rate_ctrl_mutex);
+	list_for_each_entry(alg, &rate_ctrl_algs, list) {
+		if (!strcmp(alg->ops->name, ops->name)) {
+			/* don't register an algorithm twice */
+			WARN_ON(1);
+			mutex_unlock(&rate_ctrl_mutex);
+			return -EALREADY;
+		}
+	}
+
 	alg = kzalloc(sizeof(*alg), GFP_KERNEL);
 	if (alg == NULL) {
+		mutex_unlock(&rate_ctrl_mutex);
 		return -ENOMEM;
 	}
 	alg->ops = ops;
 
-	mutex_lock(&rate_ctrl_mutex);
 	list_add_tail(&alg->list, &rate_ctrl_algs);
 	mutex_unlock(&rate_ctrl_mutex);
 
@@ -47,11 +65,11 @@ void ieee80211_rate_control_unregister(struct rate_control_ops *ops)
 	list_for_each_entry(alg, &rate_ctrl_algs, list) {
 		if (alg->ops == ops) {
 			list_del(&alg->list);
+			kfree(alg);
 			break;
 		}
 	}
 	mutex_unlock(&rate_ctrl_mutex);
-	kfree(alg);
 }
 EXPORT_SYMBOL(ieee80211_rate_control_unregister);
 
@@ -61,9 +79,12 @@ ieee80211_try_rate_control_ops_get(const char *name)
 	struct rate_control_alg *alg;
 	struct rate_control_ops *ops = NULL;
 
+	if (!name)
+		return NULL;
+
 	mutex_lock(&rate_ctrl_mutex);
 	list_for_each_entry(alg, &rate_ctrl_algs, list) {
-		if (!name || !strcmp(alg->ops->name, name))
+		if (!strcmp(alg->ops->name, name))
 			if (try_module_get(alg->ops->module)) {
 				ops = alg->ops;
 				break;
@@ -73,18 +94,31 @@ ieee80211_try_rate_control_ops_get(const char *name)
 	return ops;
 }
 
-/* Get the rate control algorithm. If `name' is NULL, get the first
- * available algorithm. */
+/* Get the rate control algorithm. */
 static struct rate_control_ops *
 ieee80211_rate_control_ops_get(const char *name)
 {
 	struct rate_control_ops *ops;
+	const char *alg_name;
 
-	ops = ieee80211_try_rate_control_ops_get(name);
+	if (!name)
+		alg_name = ieee80211_default_rc_algo;
+	else
+		alg_name = name;
+
+	ops = ieee80211_try_rate_control_ops_get(alg_name);
 	if (!ops) {
-		request_module("rc80211_%s", name ? name : "default");
-		ops = ieee80211_try_rate_control_ops_get(name);
+		request_module("rc80211_%s", alg_name);
+		ops = ieee80211_try_rate_control_ops_get(alg_name);
 	}
+	if (!ops && name)
+		/* try default if specific alg requested but not found */
+		ops = ieee80211_try_rate_control_ops_get(ieee80211_default_rc_algo);
+
+	/* try built-in one if specific alg requested but not found */
+	if (!ops && strlen(CONFIG_MAC80211_RC_DEFAULT))
+		ops = ieee80211_try_rate_control_ops_get(CONFIG_MAC80211_RC_DEFAULT);
+
 	return ops;
 }
 
@@ -128,6 +162,38 @@ static void rate_control_release(struct kref *kref)
 	kfree(ctrl_ref);
 }
 
+void rate_control_get_rate(struct net_device *dev,
+			   struct ieee80211_supported_band *sband,
+			   struct sk_buff *skb,
+			   struct rate_selection *sel)
+{
+	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+	struct rate_control_ref *ref = local->rate_ctrl;
+	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
+	struct sta_info *sta = sta_info_get(local, hdr->addr1);
+	int i;
+
+	memset(sel, 0, sizeof(struct rate_selection));
+
+	ref->ops->get_rate(ref->priv, dev, sband, skb, sel);
+
+	/* Select a non-ERP backup rate. */
+	if (!sel->nonerp) {
+		for (i = 0; i < sband->n_bitrates; i++) {
+			struct ieee80211_rate *rate = &sband->bitrates[i];
+			if (sel->rate->bitrate < rate->bitrate)
+				break;
+
+			if (rate_supported(sta, sband->band, i) &&
+			    !(rate->flags & IEEE80211_RATE_ERP_G))
+				sel->nonerp = rate;
+		}
+	}
+
+	if (sta)
+		sta_info_put(sta);
+}
+
 struct rate_control_ref *rate_control_get(struct rate_control_ref *ref)
 {
 	kref_get(&ref->kref);
@@ -178,3 +244,4 @@ void rate_control_deinitialize(struct ieee80211_local *local)
 	local->rate_ctrl = NULL;
 	rate_control_put(ref);
 }
+
diff --git a/package/mac80211/src/net/mac80211/ieee80211_rate.h b/package/mac80211/src/net/mac80211/ieee80211_rate.h
index 7cd1ebab4f..5f9a2ca49a 100644
--- a/package/mac80211/src/net/mac80211/ieee80211_rate.h
+++ b/package/mac80211/src/net/mac80211/ieee80211_rate.h
@@ -18,31 +18,26 @@
 #include "ieee80211_i.h"
 #include "sta_info.h"
 
-#define RATE_CONTROL_NUM_DOWN 20
-#define RATE_CONTROL_NUM_UP   15
-
-
-struct rate_control_extra {
-	/* values from rate_control_get_rate() to the caller: */
-	struct ieee80211_rate *probe; /* probe with this rate, or NULL for no
-				       * probing */
+/* TODO: kdoc */
+struct rate_selection {
+	/* Selected transmission rate */
+	struct ieee80211_rate *rate;
+	/* Non-ERP rate to use if mac80211 decides it cannot use an ERP rate */
 	struct ieee80211_rate *nonerp;
-
-	/* parameters from the caller to rate_control_get_rate(): */
-	struct ieee80211_hw_mode *mode;
-	u16 ethertype;
+	/* probe with this rate, or NULL for no probing */
+	struct ieee80211_rate *probe;
 };
 
-
 struct rate_control_ops {
 	struct module *module;
 	const char *name;
 	void (*tx_status)(void *priv, struct net_device *dev,
 			  struct sk_buff *skb,
 			  struct ieee80211_tx_status *status);
-	struct ieee80211_rate *(*get_rate)(void *priv, struct net_device *dev,
-					   struct sk_buff *skb,
-					   struct rate_control_extra *extra);
+	void (*get_rate)(void *priv, struct net_device *dev,
+			 struct ieee80211_supported_band *band,
+			 struct sk_buff *skb,
+			 struct rate_selection *sel);
 	void (*rate_init)(void *priv, void *priv_sta,
 			  struct ieee80211_local *local, struct sta_info *sta);
 	void (*clear)(void *priv);
@@ -72,25 +67,21 @@ void ieee80211_rate_control_unregister(struct rate_control_ops *ops);
  * first available algorithm. */
 struct rate_control_ref *rate_control_alloc(const char *name,
 					    struct ieee80211_local *local);
+void rate_control_get_rate(struct net_device *dev,
+			   struct ieee80211_supported_band *sband,
+			   struct sk_buff *skb,
+			   struct rate_selection *sel);
 struct rate_control_ref *rate_control_get(struct rate_control_ref *ref);
 void rate_control_put(struct rate_control_ref *ref);
 
-static inline void rate_control_tx_status(struct ieee80211_local *local,
-					  struct net_device *dev,
+static inline void rate_control_tx_status(struct net_device *dev,
 					  struct sk_buff *skb,
 					  struct ieee80211_tx_status *status)
 {
+	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
 	struct rate_control_ref *ref = local->rate_ctrl;
-	ref->ops->tx_status(ref->priv, dev, skb, status);
-}
-
 
-static inline struct ieee80211_rate *
-rate_control_get_rate(struct ieee80211_local *local, struct net_device *dev,
-		      struct sk_buff *skb, struct rate_control_extra *extra)
-{
-	struct rate_control_ref *ref = local->rate_ctrl;
-	return ref->ops->get_rate(ref->priv, dev, skb, extra);
+	ref->ops->tx_status(ref->priv, dev, skb, status);
 }
 
 
@@ -139,10 +130,74 @@ static inline void rate_control_remove_sta_debugfs(struct sta_info *sta)
 #endif
 }
 
+static inline int rate_supported(struct sta_info *sta,
+				 enum ieee80211_band band,
+				 int index)
+{
+	return (sta == NULL || sta->supp_rates[band] & BIT(index));
+}
+
+static inline int
+rate_lowest_index(struct ieee80211_local *local,
+		  struct ieee80211_supported_band *sband,
+		  struct sta_info *sta)
+{
+	int i;
+
+	for (i = 0; i < sband->n_bitrates; i++)
+		if (rate_supported(sta, sband->band, i))
+			return i;
+
+	/* warn when we cannot find a rate. */
+	WARN_ON(1);
+
+	return 0;
+}
+
+static inline struct ieee80211_rate *
+rate_lowest(struct ieee80211_local *local,
+	    struct ieee80211_supported_band *sband,
+	    struct sta_info *sta)
+{
+	return &sband->bitrates[rate_lowest_index(local, sband, sta)];
+}
+
 
 /* functions for rate control related to a device */
 int ieee80211_init_rate_ctrl_alg(struct ieee80211_local *local,
 				 const char *name);
 void rate_control_deinitialize(struct ieee80211_local *local);
 
+
+/* Rate control algorithms */
+#if defined(RC80211_SIMPLE_COMPILE) || \
+	(defined(CONFIG_MAC80211_RC_SIMPLE) && \
+	 !defined(CONFIG_MAC80211_RC_SIMPLE_MODULE))
+extern int rc80211_simple_init(void);
+extern void rc80211_simple_exit(void);
+#else
+static inline int rc80211_simple_init(void)
+{
+	return 0;
+}
+static inline void rc80211_simple_exit(void)
+{
+}
+#endif
+
+#if defined(RC80211_PID_COMPILE) || \
+	(defined(CONFIG_MAC80211_RC_PID) && \
+	 !defined(CONFIG_MAC80211_RC_PID_MODULE))
+extern int rc80211_pid_init(void);
+extern void rc80211_pid_exit(void);
+#else
+static inline int rc80211_pid_init(void)
+{
+	return 0;
+}
+static inline void rc80211_pid_exit(void)
+{
+}
+#endif
+
 #endif /* IEEE80211_RATE_H */
diff --git a/package/mac80211/src/net/mac80211/ieee80211_sta.c b/package/mac80211/src/net/mac80211/ieee80211_sta.c
index 7c93f29c8b..92d7450e2c 100644
--- a/package/mac80211/src/net/mac80211/ieee80211_sta.c
+++ b/package/mac80211/src/net/mac80211/ieee80211_sta.c
@@ -12,7 +12,6 @@
  */
 
 /* TODO:
- * BSS table: use <BSSID,SSID> as the key to support multi-SSID APs
  * order BSS list by RSSI(?) ("quality of AP")
  * scan result table filtering (by capability (privacy, IBSS/BSS, WPA/RSN IE,
  *    SSID)
@@ -58,10 +57,25 @@
 
 #define ERP_INFO_USE_PROTECTION BIT(1)
 
+/* mgmt header + 1 byte action code */
+#define IEEE80211_MIN_ACTION_SIZE (24 + 1)
+
+#define IEEE80211_ADDBA_PARAM_POLICY_MASK 0x0002
+#define IEEE80211_ADDBA_PARAM_TID_MASK 0x003C
+#define IEEE80211_ADDBA_PARAM_BUF_SIZE_MASK 0xFFA0
+#define IEEE80211_DELBA_PARAM_TID_MASK 0xF000
+#define IEEE80211_DELBA_PARAM_INITIATOR_MASK 0x0800
+
+/* next values represent the buffer size for A-MPDU frame.
+ * According to IEEE802.11n spec size varies from 8K to 64K (in powers of 2) */
+#define IEEE80211_MIN_AMPDU_BUF 0x8
+#define IEEE80211_MAX_AMPDU_BUF 0x40
+
 static void ieee80211_send_probe_req(struct net_device *dev, u8 *dst,
 				     u8 *ssid, size_t ssid_len);
 static struct ieee80211_sta_bss *
-ieee80211_rx_bss_get(struct net_device *dev, u8 *bssid);
+ieee80211_rx_bss_get(struct net_device *dev, u8 *bssid, int freq,
+		     u8 *ssid, u8 ssid_len);
 static void ieee80211_rx_bss_put(struct net_device *dev,
 				 struct ieee80211_sta_bss *bss);
 static int ieee80211_sta_find_ibss(struct net_device *dev,
@@ -90,7 +104,8 @@ struct ieee802_11_elems {
 	u8 *ext_supp_rates;
 	u8 *wmm_info;
 	u8 *wmm_param;
-
+	u8 *ht_cap_elem;
+	u8 *ht_info_elem;
 	/* length of them, respectively */
 	u8 ssid_len;
 	u8 supp_rates_len;
@@ -106,16 +121,15 @@ struct ieee802_11_elems {
 	u8 ext_supp_rates_len;
 	u8 wmm_info_len;
 	u8 wmm_param_len;
+	u8 ht_cap_elem_len;
+	u8 ht_info_elem_len;
 };
 
-enum ParseRes { ParseOK = 0, ParseUnknown = 1, ParseFailed = -1 };
-
-static enum ParseRes ieee802_11_parse_elems(u8 *start, size_t len,
-					    struct ieee802_11_elems *elems)
+static void ieee802_11_parse_elems(u8 *start, size_t len,
+				   struct ieee802_11_elems *elems)
 {
 	size_t left = len;
 	u8 *pos = start;
-	int unknown = 0;
 
 	memset(elems, 0, sizeof(*elems));
 
@@ -126,15 +140,8 @@ static enum ParseRes ieee802_11_parse_elems(u8 *start, size_t len,
 		elen = *pos++;
 		left -= 2;
 
-		if (elen > left) {
-#if 0
-			if (net_ratelimit())
-				printk(KERN_DEBUG "IEEE 802.11 element parse "
-				       "failed (id=%d elen=%d left=%d)\n",
-				       id, elen, left);
-#endif
-			return ParseFailed;
-		}
+		if (elen > left)
+			return;
 
 		switch (id) {
 		case WLAN_EID_SSID:
@@ -200,29 +207,24 @@ static enum ParseRes ieee802_11_parse_elems(u8 *start, size_t len,
 			elems->ext_supp_rates = pos;
 			elems->ext_supp_rates_len = elen;
 			break;
+		case WLAN_EID_HT_CAPABILITY:
+			elems->ht_cap_elem = pos;
+			elems->ht_cap_elem_len = elen;
+			break;
+		case WLAN_EID_HT_EXTRA_INFO:
+			elems->ht_info_elem = pos;
+			elems->ht_info_elem_len = elen;
+			break;
 		default:
-#if 0
-			printk(KERN_DEBUG "IEEE 802.11 element parse ignored "
-				      "unknown element (id=%d elen=%d)\n",
-				      id, elen);
-#endif
-			unknown++;
 			break;
 		}
 
 		left -= elen;
 		pos += elen;
 	}
-
-	/* Do not trigger error if left == 1 as Apple Airport base stations
-	 * send AssocResps that are one spurious byte too long. */
-
-	return unknown ? ParseUnknown : ParseOK;
 }
 
 
-
-
 static int ecw2cw(int ecw)
 {
 	int cw = 1;
@@ -311,49 +313,89 @@ static void ieee80211_sta_wmm_params(struct net_device *dev,
 }
 
 
-static void ieee80211_handle_erp_ie(struct net_device *dev, u8 erp_value)
+static u32 ieee80211_handle_erp_ie(struct ieee80211_sub_if_data *sdata,
+				   u8 erp_value)
 {
-	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+	struct ieee80211_bss_conf *bss_conf = &sdata->bss_conf;
 	struct ieee80211_if_sta *ifsta = &sdata->u.sta;
-	int use_protection = (erp_value & WLAN_ERP_USE_PROTECTION) != 0;
-	int preamble_mode = (erp_value & WLAN_ERP_BARKER_PREAMBLE) != 0;
-	u8 changes = 0;
+	bool use_protection = (erp_value & WLAN_ERP_USE_PROTECTION) != 0;
+	bool preamble_mode = (erp_value & WLAN_ERP_BARKER_PREAMBLE) != 0;
+	DECLARE_MAC_BUF(mac);
+	u32 changed = 0;
 
-	if (use_protection != !!(sdata->flags & IEEE80211_SDATA_USE_PROTECTION)) {
+	if (use_protection != bss_conf->use_cts_prot) {
 		if (net_ratelimit()) {
 			printk(KERN_DEBUG "%s: CTS protection %s (BSSID="
-			       MAC_FMT ")\n",
-			       dev->name,
+			       "%s)\n",
+			       sdata->dev->name,
 			       use_protection ? "enabled" : "disabled",
-			       MAC_ARG(ifsta->bssid));
+			       print_mac(mac, ifsta->bssid));
 		}
-		if (use_protection)
-			sdata->flags |= IEEE80211_SDATA_USE_PROTECTION;
-		else
-			sdata->flags &= ~IEEE80211_SDATA_USE_PROTECTION;
-		changes |= IEEE80211_ERP_CHANGE_PROTECTION;
+		bss_conf->use_cts_prot = use_protection;
+		changed |= BSS_CHANGED_ERP_CTS_PROT;
 	}
 
-	if (preamble_mode != !(sdata->flags & IEEE80211_SDATA_SHORT_PREAMBLE)) {
+	if (preamble_mode != bss_conf->use_short_preamble) {
 		if (net_ratelimit()) {
 			printk(KERN_DEBUG "%s: switched to %s barker preamble"
-			       " (BSSID=" MAC_FMT ")\n",
-			       dev->name,
+			       " (BSSID=%s)\n",
+			       sdata->dev->name,
 			       (preamble_mode == WLAN_ERP_PREAMBLE_SHORT) ?
 					"short" : "long",
-			       MAC_ARG(ifsta->bssid));
+			       print_mac(mac, ifsta->bssid));
 		}
-		if (preamble_mode)
-			sdata->flags &= ~IEEE80211_SDATA_SHORT_PREAMBLE;
-		else
-			sdata->flags |= IEEE80211_SDATA_SHORT_PREAMBLE;
-		changes |= IEEE80211_ERP_CHANGE_PREAMBLE;
+		bss_conf->use_short_preamble = preamble_mode;
+		changed |= BSS_CHANGED_ERP_PREAMBLE;
 	}
 
-	if (changes)
-		ieee80211_erp_info_change_notify(dev, changes);
+	return changed;
+}
+
+int ieee80211_ht_cap_ie_to_ht_info(struct ieee80211_ht_cap *ht_cap_ie,
+				   struct ieee80211_ht_info *ht_info)
+{
+
+	if (ht_info == NULL)
+		return -EINVAL;
+
+	memset(ht_info, 0, sizeof(*ht_info));
+
+	if (ht_cap_ie) {
+		u8 ampdu_info = ht_cap_ie->ampdu_params_info;
+
+		ht_info->ht_supported = 1;
+		ht_info->cap = le16_to_cpu(ht_cap_ie->cap_info);
+		ht_info->ampdu_factor =
+			ampdu_info & IEEE80211_HT_CAP_AMPDU_FACTOR;
+		ht_info->ampdu_density =
+			(ampdu_info & IEEE80211_HT_CAP_AMPDU_DENSITY) >> 2;
+		memcpy(ht_info->supp_mcs_set, ht_cap_ie->supp_mcs_set, 16);
+	} else
+		ht_info->ht_supported = 0;
+
+	return 0;
 }
 
+int ieee80211_ht_addt_info_ie_to_ht_bss_info(
+			struct ieee80211_ht_addt_info *ht_add_info_ie,
+			struct ieee80211_ht_bss_info *bss_info)
+{
+	if (bss_info == NULL)
+		return -EINVAL;
+
+	memset(bss_info, 0, sizeof(*bss_info));
+
+	if (ht_add_info_ie) {
+		u16 op_mode;
+		op_mode = le16_to_cpu(ht_add_info_ie->operation_mode);
+
+		bss_info->primary_channel = ht_add_info_ie->control_chan;
+		bss_info->bss_cap = ht_add_info_ie->ht_param;
+		bss_info->bss_op_mode = (u8)(op_mode & 0xff);
+	}
+
+	return 0;
+}
 
 static void ieee80211_sta_send_associnfo(struct net_device *dev,
 					 struct ieee80211_if_sta *ifsta)
@@ -410,26 +452,26 @@ static void ieee80211_set_associated(struct net_device *dev,
 				     struct ieee80211_if_sta *ifsta,
 				     bool assoc)
 {
-	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+	struct ieee80211_local *local = sdata->local;
 	union iwreq_data wrqu;
-
-	if (!!(ifsta->flags & IEEE80211_STA_ASSOCIATED) == assoc)
-		return;
+	u32 changed = BSS_CHANGED_ASSOC;
 
 	if (assoc) {
-		struct ieee80211_sub_if_data *sdata;
 		struct ieee80211_sta_bss *bss;
 
 		ifsta->flags |= IEEE80211_STA_ASSOCIATED;
 
-		sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-		if (sdata->type != IEEE80211_IF_TYPE_STA)
+		if (sdata->vif.type != IEEE80211_IF_TYPE_STA)
 			return;
 
-		bss = ieee80211_rx_bss_get(dev, ifsta->bssid);
+		bss = ieee80211_rx_bss_get(dev, ifsta->bssid,
+					   local->hw.conf.channel->center_freq,
+					   ifsta->ssid, ifsta->ssid_len);
 		if (bss) {
 			if (bss->has_erp_value)
-				ieee80211_handle_erp_ie(dev, bss->erp_value);
+				changed |= ieee80211_handle_erp_ie(
+						sdata, bss->erp_value);
 			ieee80211_rx_bss_put(dev, bss);
 		}
 
@@ -449,6 +491,9 @@ static void ieee80211_set_associated(struct net_device *dev,
 	wireless_send_event(dev, SIOCGIWAP, &wrqu, NULL);
 	ifsta->last_probe = jiffies;
 	ieee80211_led_assoc(local, assoc);
+
+	sdata->bss_conf.assoc = assoc;
+	ieee80211_bss_info_change_notify(sdata, changed);
 }
 
 static void ieee80211_set_disassoc(struct net_device *dev,
@@ -523,18 +568,20 @@ static void ieee80211_send_auth(struct net_device *dev,
 static void ieee80211_authenticate(struct net_device *dev,
 				   struct ieee80211_if_sta *ifsta)
 {
+	DECLARE_MAC_BUF(mac);
+
 	ifsta->auth_tries++;
 	if (ifsta->auth_tries > IEEE80211_AUTH_MAX_TRIES) {
-		printk(KERN_DEBUG "%s: authentication with AP " MAC_FMT
+		printk(KERN_DEBUG "%s: authentication with AP %s"
 		       " timed out\n",
-		       dev->name, MAC_ARG(ifsta->bssid));
+		       dev->name, print_mac(mac, ifsta->bssid));
 		ifsta->state = IEEE80211_DISABLED;
 		return;
 	}
 
 	ifsta->state = IEEE80211_AUTHENTICATE;
-	printk(KERN_DEBUG "%s: authenticate with AP " MAC_FMT "\n",
-	       dev->name, MAC_ARG(ifsta->bssid));
+	printk(KERN_DEBUG "%s: authenticate with AP %s\n",
+	       dev->name, print_mac(mac, ifsta->bssid));
 
 	ieee80211_send_auth(dev, ifsta, 1, NULL, 0, 0);
 
@@ -546,7 +593,6 @@ static void ieee80211_send_assoc(struct net_device *dev,
 				 struct ieee80211_if_sta *ifsta)
 {
 	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
-	struct ieee80211_hw_mode *mode;
 	struct sk_buff *skb;
 	struct ieee80211_mgmt *mgmt;
 	u8 *pos, *ies;
@@ -554,6 +600,7 @@ static void ieee80211_send_assoc(struct net_device *dev,
 	u16 capab;
 	struct ieee80211_sta_bss *bss;
 	int wmm = 0;
+	struct ieee80211_supported_band *sband;
 
 	skb = dev_alloc_skb(local->hw.extra_tx_headroom +
 			    sizeof(*mgmt) + 200 + ifsta->extra_ie_len +
@@ -565,13 +612,20 @@ static void ieee80211_send_assoc(struct net_device *dev,
 	}
 	skb_reserve(skb, local->hw.extra_tx_headroom);
 
-	mode = local->oper_hw_mode;
+	sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
+
 	capab = ifsta->capab;
-	if (mode->mode == MODE_IEEE80211G) {
-		capab |= WLAN_CAPABILITY_SHORT_SLOT_TIME |
-			WLAN_CAPABILITY_SHORT_PREAMBLE;
+
+	if (local->hw.conf.channel->band == IEEE80211_BAND_2GHZ) {
+		if (!(local->hw.flags & IEEE80211_HW_2GHZ_SHORT_SLOT_INCAPABLE))
+			capab |= WLAN_CAPABILITY_SHORT_SLOT_TIME;
+		if (!(local->hw.flags & IEEE80211_HW_2GHZ_SHORT_PREAMBLE_INCAPABLE))
+			capab |= WLAN_CAPABILITY_SHORT_PREAMBLE;
 	}
-	bss = ieee80211_rx_bss_get(dev, ifsta->bssid);
+
+	bss = ieee80211_rx_bss_get(dev, ifsta->bssid,
+				   local->hw.conf.channel->center_freq,
+				   ifsta->ssid, ifsta->ssid_len);
 	if (bss) {
 		if (bss->capability & WLAN_CAPABILITY_PRIVACY)
 			capab |= WLAN_CAPABILITY_PRIVACY;
@@ -609,23 +663,23 @@ static void ieee80211_send_assoc(struct net_device *dev,
 	*pos++ = ifsta->ssid_len;
 	memcpy(pos, ifsta->ssid, ifsta->ssid_len);
 
-	len = mode->num_rates;
+	len = sband->n_bitrates;
 	if (len > 8)
 		len = 8;
 	pos = skb_put(skb, len + 2);
 	*pos++ = WLAN_EID_SUPP_RATES;
 	*pos++ = len;
 	for (i = 0; i < len; i++) {
-		int rate = mode->rates[i].rate;
+		int rate = sband->bitrates[i].bitrate;
 		*pos++ = (u8) (rate / 5);
 	}
 
-	if (mode->num_rates > len) {
-		pos = skb_put(skb, mode->num_rates - len + 2);
+	if (sband->n_bitrates > len) {
+		pos = skb_put(skb, sband->n_bitrates - len + 2);
 		*pos++ = WLAN_EID_EXT_SUPP_RATES;
-		*pos++ = mode->num_rates - len;
-		for (i = len; i < mode->num_rates; i++) {
-			int rate = mode->rates[i].rate;
+		*pos++ = sband->n_bitrates - len;
+		for (i = len; i < sband->n_bitrates; i++) {
+			int rate = sband->bitrates[i].bitrate;
 			*pos++ = (u8) (rate / 5);
 		}
 	}
@@ -647,6 +701,20 @@ static void ieee80211_send_assoc(struct net_device *dev,
 		*pos++ = 1; /* WME ver */
 		*pos++ = 0;
 	}
+	/* wmm support is a must to HT */
+	if (wmm && sband->ht_info.ht_supported) {
+		__le16 tmp = cpu_to_le16(sband->ht_info.cap);
+		pos = skb_put(skb, sizeof(struct ieee80211_ht_cap)+2);
+		*pos++ = WLAN_EID_HT_CAPABILITY;
+		*pos++ = sizeof(struct ieee80211_ht_cap);
+		memset(pos, 0, sizeof(struct ieee80211_ht_cap));
+		memcpy(pos, &tmp, sizeof(u16));
+		pos += sizeof(u16);
+		/* TODO: needs a define here for << 2 */
+		*pos++ = sband->ht_info.ampdu_factor |
+			 (sband->ht_info.ampdu_density << 2);
+		memcpy(pos, sband->ht_info.supp_mcs_set, 16);
+	}
 
 	kfree(ifsta->assocreq_ies);
 	ifsta->assocreq_ies_len = (skb->data + skb->len) - ies;
@@ -719,42 +787,51 @@ static void ieee80211_send_disassoc(struct net_device *dev,
 static int ieee80211_privacy_mismatch(struct net_device *dev,
 				      struct ieee80211_if_sta *ifsta)
 {
+	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
 	struct ieee80211_sta_bss *bss;
-	int res = 0;
+	int bss_privacy;
+	int wep_privacy;
+	int privacy_invoked;
 
-	if (!ifsta || (ifsta->flags & IEEE80211_STA_MIXED_CELL) ||
-	    ifsta->key_management_enabled)
+	if (!ifsta || (ifsta->flags & IEEE80211_STA_MIXED_CELL))
 		return 0;
 
-	bss = ieee80211_rx_bss_get(dev, ifsta->bssid);
+	bss = ieee80211_rx_bss_get(dev, ifsta->bssid,
+				   local->hw.conf.channel->center_freq,
+				   ifsta->ssid, ifsta->ssid_len);
 	if (!bss)
 		return 0;
 
-	if (ieee80211_sta_wep_configured(dev) !=
-	    !!(bss->capability & WLAN_CAPABILITY_PRIVACY))
-		res = 1;
+	bss_privacy = !!(bss->capability & WLAN_CAPABILITY_PRIVACY);
+	wep_privacy = !!ieee80211_sta_wep_configured(dev);
+	privacy_invoked = !!(ifsta->flags & IEEE80211_STA_PRIVACY_INVOKED);
 
 	ieee80211_rx_bss_put(dev, bss);
 
-	return res;
+	if ((bss_privacy == wep_privacy) || (bss_privacy == privacy_invoked))
+		return 0;
+
+	return 1;
 }
 
 
 static void ieee80211_associate(struct net_device *dev,
 				struct ieee80211_if_sta *ifsta)
 {
+	DECLARE_MAC_BUF(mac);
+
 	ifsta->assoc_tries++;
 	if (ifsta->assoc_tries > IEEE80211_ASSOC_MAX_TRIES) {
-		printk(KERN_DEBUG "%s: association with AP " MAC_FMT
+		printk(KERN_DEBUG "%s: association with AP %s"
 		       " timed out\n",
-		       dev->name, MAC_ARG(ifsta->bssid));
+		       dev->name, print_mac(mac, ifsta->bssid));
 		ifsta->state = IEEE80211_DISABLED;
 		return;
 	}
 
 	ifsta->state = IEEE80211_ASSOCIATE;
-	printk(KERN_DEBUG "%s: associate with AP " MAC_FMT "\n",
-	       dev->name, MAC_ARG(ifsta->bssid));
+	printk(KERN_DEBUG "%s: associate with AP %s\n",
+	       dev->name, print_mac(mac, ifsta->bssid));
 	if (ieee80211_privacy_mismatch(dev, ifsta)) {
 		printk(KERN_DEBUG "%s: mismatch in privacy configuration and "
 		       "mixed-cell disabled - abort association\n", dev->name);
@@ -774,6 +851,7 @@ static void ieee80211_associated(struct net_device *dev,
 	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
 	struct sta_info *sta;
 	int disassoc;
+	DECLARE_MAC_BUF(mac);
 
 	/* TODO: start monitoring current AP signal quality and number of
 	 * missed beacons. Scan other channels every now and then and search
@@ -784,8 +862,8 @@ static void ieee80211_associated(struct net_device *dev,
 
 	sta = sta_info_get(local, ifsta->bssid);
 	if (!sta) {
-		printk(KERN_DEBUG "%s: No STA entry for own AP " MAC_FMT "\n",
-		       dev->name, MAC_ARG(ifsta->bssid));
+		printk(KERN_DEBUG "%s: No STA entry for own AP %s\n",
+		       dev->name, print_mac(mac, ifsta->bssid));
 		disassoc = 1;
 	} else {
 		disassoc = 0;
@@ -793,9 +871,9 @@ static void ieee80211_associated(struct net_device *dev,
 			       sta->last_rx + IEEE80211_MONITORING_INTERVAL)) {
 			if (ifsta->flags & IEEE80211_STA_PROBEREQ_POLL) {
 				printk(KERN_DEBUG "%s: No ProbeResp from "
-				       "current AP " MAC_FMT " - assume out of "
+				       "current AP %s - assume out of "
 				       "range\n",
-				       dev->name, MAC_ARG(ifsta->bssid));
+				       dev->name, print_mac(mac, ifsta->bssid));
 				disassoc = 1;
 				sta_info_free(sta);
 			} else
@@ -816,12 +894,8 @@ static void ieee80211_associated(struct net_device *dev,
 		sta_info_put(sta);
 	}
 	if (disassoc) {
-		union iwreq_data wrqu;
-		memset(wrqu.ap_addr.sa_data, 0, ETH_ALEN);
-		wrqu.ap_addr.sa_family = ARPHRD_ETHER;
-		wireless_send_event(dev, SIOCGIWAP, &wrqu, NULL);
-		mod_timer(&ifsta->timer, jiffies +
-				      IEEE80211_MONITORING_INTERVAL + 30 * HZ);
+		ifsta->state = IEEE80211_DISABLED;
+		ieee80211_set_associated(dev, ifsta, 0);
 	} else {
 		mod_timer(&ifsta->timer, jiffies +
 				      IEEE80211_MONITORING_INTERVAL);
@@ -833,7 +907,7 @@ static void ieee80211_send_probe_req(struct net_device *dev, u8 *dst,
 				     u8 *ssid, size_t ssid_len)
 {
 	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
-	struct ieee80211_hw_mode *mode;
+	struct ieee80211_supported_band *sband;
 	struct sk_buff *skb;
 	struct ieee80211_mgmt *mgmt;
 	u8 *pos, *supp_rates, *esupp_rates = NULL;
@@ -867,11 +941,10 @@ static void ieee80211_send_probe_req(struct net_device *dev, u8 *dst,
 	supp_rates = skb_put(skb, 2);
 	supp_rates[0] = WLAN_EID_SUPP_RATES;
 	supp_rates[1] = 0;
-	mode = local->oper_hw_mode;
-	for (i = 0; i < mode->num_rates; i++) {
-		struct ieee80211_rate *rate = &mode->rates[i];
-		if (!(rate->flags & IEEE80211_RATE_SUPPORTED))
-			continue;
+	sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
+
+	for (i = 0; i < sband->n_bitrates; i++) {
+		struct ieee80211_rate *rate = &sband->bitrates[i];
 		if (esupp_rates) {
 			pos = skb_put(skb, 1);
 			esupp_rates[1]++;
@@ -884,7 +957,7 @@ static void ieee80211_send_probe_req(struct net_device *dev, u8 *dst,
 			pos = skb_put(skb, 1);
 			supp_rates[1]++;
 		}
-		*pos = rate->rate / 5;
+		*pos = rate->bitrate / 5;
 	}
 
 	ieee80211_sta_tx(dev, skb, 0);
@@ -920,12 +993,7 @@ static void ieee80211_auth_challenge(struct net_device *dev,
 
 	printk(KERN_DEBUG "%s: replying to auth challenge\n", dev->name);
 	pos = mgmt->u.auth.variable;
-	if (ieee802_11_parse_elems(pos, len - (pos - (u8 *) mgmt), &elems)
-	    == ParseFailed) {
-		printk(KERN_DEBUG "%s: failed to parse Auth(challenge)\n",
-		       dev->name);
-		return;
-	}
+	ieee802_11_parse_elems(pos, len - (pos - (u8 *) mgmt), &elems);
 	if (!elems.challenge) {
 		printk(KERN_DEBUG "%s: no challenge IE in shared key auth "
 		       "frame\n", dev->name);
@@ -935,6 +1003,503 @@ static void ieee80211_auth_challenge(struct net_device *dev,
 			    elems.challenge_len + 2, 1);
 }
 
+static void ieee80211_send_addba_resp(struct net_device *dev, u8 *da, u16 tid,
+					u8 dialog_token, u16 status, u16 policy,
+					u16 buf_size, u16 timeout)
+{
+	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+	struct ieee80211_if_sta *ifsta = &sdata->u.sta;
+	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+	struct sk_buff *skb;
+	struct ieee80211_mgmt *mgmt;
+	u16 capab;
+
+	skb = dev_alloc_skb(sizeof(*mgmt) + local->hw.extra_tx_headroom + 1 +
+					sizeof(mgmt->u.action.u.addba_resp));
+	if (!skb) {
+		printk(KERN_DEBUG "%s: failed to allocate buffer "
+		       "for addba resp frame\n", dev->name);
+		return;
+	}
+
+	skb_reserve(skb, local->hw.extra_tx_headroom);
+	mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24);
+	memset(mgmt, 0, 24);
+	memcpy(mgmt->da, da, ETH_ALEN);
+	memcpy(mgmt->sa, dev->dev_addr, ETH_ALEN);
+	if (sdata->vif.type == IEEE80211_IF_TYPE_AP)
+		memcpy(mgmt->bssid, dev->dev_addr, ETH_ALEN);
+	else
+		memcpy(mgmt->bssid, ifsta->bssid, ETH_ALEN);
+	mgmt->frame_control = IEEE80211_FC(IEEE80211_FTYPE_MGMT,
+					   IEEE80211_STYPE_ACTION);
+
+	skb_put(skb, 1 + sizeof(mgmt->u.action.u.addba_resp));
+	mgmt->u.action.category = WLAN_CATEGORY_BACK;
+	mgmt->u.action.u.addba_resp.action_code = WLAN_ACTION_ADDBA_RESP;
+	mgmt->u.action.u.addba_resp.dialog_token = dialog_token;
+
+	capab = (u16)(policy << 1);	/* bit 1 aggregation policy */
+	capab |= (u16)(tid << 2); 	/* bit 5:2 TID number */
+	capab |= (u16)(buf_size << 6);	/* bit 15:6 max size of aggregation */
+
+	mgmt->u.action.u.addba_resp.capab = cpu_to_le16(capab);
+	mgmt->u.action.u.addba_resp.timeout = cpu_to_le16(timeout);
+	mgmt->u.action.u.addba_resp.status = cpu_to_le16(status);
+
+	ieee80211_sta_tx(dev, skb, 0);
+
+	return;
+}
+
+void ieee80211_send_addba_request(struct net_device *dev, const u8 *da,
+				u16 tid, u8 dialog_token, u16 start_seq_num,
+				u16 agg_size, u16 timeout)
+{
+	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+	struct ieee80211_if_sta *ifsta = &sdata->u.sta;
+	struct sk_buff *skb;
+	struct ieee80211_mgmt *mgmt;
+	u16 capab;
+
+	skb = dev_alloc_skb(sizeof(*mgmt) + local->hw.extra_tx_headroom + 1 +
+				sizeof(mgmt->u.action.u.addba_req));
+
+
+	if (!skb) {
+		printk(KERN_ERR "%s: failed to allocate buffer "
+				"for addba request frame\n", dev->name);
+		return;
+	}
+	skb_reserve(skb, local->hw.extra_tx_headroom);
+	mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24);
+	memset(mgmt, 0, 24);
+	memcpy(mgmt->da, da, ETH_ALEN);
+	memcpy(mgmt->sa, dev->dev_addr, ETH_ALEN);
+	if (sdata->vif.type == IEEE80211_IF_TYPE_AP)
+		memcpy(mgmt->bssid, dev->dev_addr, ETH_ALEN);
+	else
+		memcpy(mgmt->bssid, ifsta->bssid, ETH_ALEN);
+
+	mgmt->frame_control = IEEE80211_FC(IEEE80211_FTYPE_MGMT,
+					IEEE80211_STYPE_ACTION);
+
+	skb_put(skb, 1 + sizeof(mgmt->u.action.u.addba_req));
+
+	mgmt->u.action.category = WLAN_CATEGORY_BACK;
+	mgmt->u.action.u.addba_req.action_code = WLAN_ACTION_ADDBA_REQ;
+
+	mgmt->u.action.u.addba_req.dialog_token = dialog_token;
+	capab = (u16)(1 << 1);		/* bit 1 aggregation policy */
+	capab |= (u16)(tid << 2); 	/* bit 5:2 TID number */
+	capab |= (u16)(agg_size << 6);	/* bit 15:6 max size of aggergation */
+
+	mgmt->u.action.u.addba_req.capab = cpu_to_le16(capab);
+
+	mgmt->u.action.u.addba_req.timeout = cpu_to_le16(timeout);
+	mgmt->u.action.u.addba_req.start_seq_num =
+					cpu_to_le16(start_seq_num << 4);
+
+	ieee80211_sta_tx(dev, skb, 0);
+}
+
+static void ieee80211_sta_process_addba_request(struct net_device *dev,
+						struct ieee80211_mgmt *mgmt,
+						size_t len)
+{
+	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+	struct ieee80211_hw *hw = &local->hw;
+	struct ieee80211_conf *conf = &hw->conf;
+	struct sta_info *sta;
+	struct tid_ampdu_rx *tid_agg_rx;
+	u16 capab, tid, timeout, ba_policy, buf_size, start_seq_num, status;
+	u8 dialog_token;
+	int ret = -EOPNOTSUPP;
+	DECLARE_MAC_BUF(mac);
+
+	sta = sta_info_get(local, mgmt->sa);
+	if (!sta)
+		return;
+
+	/* extract session parameters from addba request frame */
+	dialog_token = mgmt->u.action.u.addba_req.dialog_token;
+	timeout = le16_to_cpu(mgmt->u.action.u.addba_req.timeout);
+	start_seq_num =
+		le16_to_cpu(mgmt->u.action.u.addba_req.start_seq_num) >> 4;
+
+	capab = le16_to_cpu(mgmt->u.action.u.addba_req.capab);
+	ba_policy = (capab & IEEE80211_ADDBA_PARAM_POLICY_MASK) >> 1;
+	tid = (capab & IEEE80211_ADDBA_PARAM_TID_MASK) >> 2;
+	buf_size = (capab & IEEE80211_ADDBA_PARAM_BUF_SIZE_MASK) >> 6;
+
+	status = WLAN_STATUS_REQUEST_DECLINED;
+
+	/* sanity check for incoming parameters:
+	 * check if configuration can support the BA policy
+	 * and if buffer size does not exceeds max value */
+	if (((ba_policy != 1)
+		&& (!(conf->ht_conf.cap & IEEE80211_HT_CAP_DELAY_BA)))
+		|| (buf_size > IEEE80211_MAX_AMPDU_BUF)) {
+		status = WLAN_STATUS_INVALID_QOS_PARAM;
+#ifdef CONFIG_MAC80211_HT_DEBUG
+		if (net_ratelimit())
+			printk(KERN_DEBUG "Block Ack Req with bad params from "
+				"%s on tid %u. policy %d, buffer size %d\n",
+				print_mac(mac, mgmt->sa), tid, ba_policy,
+				buf_size);
+#endif /* CONFIG_MAC80211_HT_DEBUG */
+		goto end_no_lock;
+	}
+	/* determine default buffer size */
+	if (buf_size == 0) {
+		struct ieee80211_supported_band *sband;
+
+		sband = local->hw.wiphy->bands[conf->channel->band];
+		buf_size = IEEE80211_MIN_AMPDU_BUF;
+		buf_size = buf_size << sband->ht_info.ampdu_factor;
+	}
+
+	tid_agg_rx = &sta->ampdu_mlme.tid_rx[tid];
+
+	/* examine state machine */
+	spin_lock_bh(&sta->ampdu_mlme.ampdu_rx);
+
+	if (tid_agg_rx->state != HT_AGG_STATE_IDLE) {
+#ifdef CONFIG_MAC80211_HT_DEBUG
+		if (net_ratelimit())
+			printk(KERN_DEBUG "unexpected Block Ack Req from "
+				"%s on tid %u\n",
+				print_mac(mac, mgmt->sa), tid);
+#endif /* CONFIG_MAC80211_HT_DEBUG */
+		goto end;
+	}
+
+	/* prepare reordering buffer */
+	tid_agg_rx->reorder_buf =
+		kmalloc(buf_size * sizeof(struct sk_buf *), GFP_ATOMIC);
+	if ((!tid_agg_rx->reorder_buf) && net_ratelimit()) {
+		printk(KERN_ERR "can not allocate reordering buffer "
+						"to tid %d\n", tid);
+		goto end;
+	}
+	memset(tid_agg_rx->reorder_buf, 0,
+		buf_size * sizeof(struct sk_buf *));
+
+	if (local->ops->ampdu_action)
+		ret = local->ops->ampdu_action(hw, IEEE80211_AMPDU_RX_START,
+					       sta->addr, tid, &start_seq_num);
+#ifdef CONFIG_MAC80211_HT_DEBUG
+	printk(KERN_DEBUG "Rx A-MPDU on tid %d result %d", tid, ret);
+#endif /* CONFIG_MAC80211_HT_DEBUG */
+
+	if (ret) {
+		kfree(tid_agg_rx->reorder_buf);
+		goto end;
+	}
+
+	/* change state and send addba resp */
+	tid_agg_rx->state = HT_AGG_STATE_OPERATIONAL;
+	tid_agg_rx->dialog_token = dialog_token;
+	tid_agg_rx->ssn = start_seq_num;
+	tid_agg_rx->head_seq_num = start_seq_num;
+	tid_agg_rx->buf_size = buf_size;
+	tid_agg_rx->timeout = timeout;
+	tid_agg_rx->stored_mpdu_num = 0;
+	status = WLAN_STATUS_SUCCESS;
+end:
+	spin_unlock_bh(&sta->ampdu_mlme.ampdu_rx);
+
+end_no_lock:
+	ieee80211_send_addba_resp(sta->dev, sta->addr, tid, dialog_token,
+				status, 1, buf_size, timeout);
+	sta_info_put(sta);
+}
+
+static void ieee80211_sta_process_addba_resp(struct net_device *dev,
+					     struct ieee80211_mgmt *mgmt,
+					     size_t len)
+{
+	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+	struct ieee80211_hw *hw = &local->hw;
+	struct sta_info *sta;
+	u16 capab;
+	u16 tid;
+	u8 *state;
+
+	sta = sta_info_get(local, mgmt->sa);
+	if (!sta)
+		return;
+
+	capab = le16_to_cpu(mgmt->u.action.u.addba_resp.capab);
+	tid = (capab & IEEE80211_ADDBA_PARAM_TID_MASK) >> 2;
+
+	state = &sta->ampdu_mlme.tid_tx[tid].state;
+
+	spin_lock_bh(&sta->ampdu_mlme.ampdu_tx);
+
+	if (mgmt->u.action.u.addba_resp.dialog_token !=
+		sta->ampdu_mlme.tid_tx[tid].dialog_token) {
+		spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx);
+#ifdef CONFIG_MAC80211_HT_DEBUG
+		printk(KERN_DEBUG "wrong addBA response token, tid %d\n", tid);
+#endif /* CONFIG_MAC80211_HT_DEBUG */
+		sta_info_put(sta);
+		return;
+	}
+
+	del_timer_sync(&sta->ampdu_mlme.tid_tx[tid].addba_resp_timer);
+#ifdef CONFIG_MAC80211_HT_DEBUG
+	printk(KERN_DEBUG "switched off addBA timer for tid %d \n", tid);
+#endif /* CONFIG_MAC80211_HT_DEBUG */
+	if (le16_to_cpu(mgmt->u.action.u.addba_resp.status)
+			== WLAN_STATUS_SUCCESS) {
+		if (!(*state & HT_ADDBA_REQUESTED_MSK)) {
+			spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx);
+			printk(KERN_DEBUG "state not HT_ADDBA_REQUESTED_MSK:"
+				"%d\n", *state);
+			sta_info_put(sta);
+			return;
+		}
+
+		if (*state & HT_ADDBA_RECEIVED_MSK)
+			printk(KERN_DEBUG "double addBA response\n");
+
+		*state |= HT_ADDBA_RECEIVED_MSK;
+		sta->ampdu_mlme.tid_tx[tid].addba_req_num = 0;
+
+		if (*state == HT_AGG_STATE_OPERATIONAL) {
+			printk(KERN_DEBUG "Aggregation on for tid %d \n", tid);
+			ieee80211_wake_queue(hw, sta->tid_to_tx_q[tid]);
+		}
+
+		spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx);
+		printk(KERN_DEBUG "recipient accepted agg: tid %d \n", tid);
+	} else {
+		printk(KERN_DEBUG "recipient rejected agg: tid %d \n", tid);
+
+		sta->ampdu_mlme.tid_tx[tid].addba_req_num++;
+		/* this will allow the state check in stop_BA_session */
+		*state = HT_AGG_STATE_OPERATIONAL;
+		spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx);
+		ieee80211_stop_tx_ba_session(hw, sta->addr, tid,
+					     WLAN_BACK_INITIATOR);
+	}
+	sta_info_put(sta);
+}
+
+void ieee80211_send_delba(struct net_device *dev, const u8 *da, u16 tid,
+			  u16 initiator, u16 reason_code)
+{
+	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+	struct ieee80211_if_sta *ifsta = &sdata->u.sta;
+	struct sk_buff *skb;
+	struct ieee80211_mgmt *mgmt;
+	u16 params;
+
+	skb = dev_alloc_skb(sizeof(*mgmt) + local->hw.extra_tx_headroom + 1 +
+					sizeof(mgmt->u.action.u.delba));
+
+	if (!skb) {
+		printk(KERN_ERR "%s: failed to allocate buffer "
+					"for delba frame\n", dev->name);
+		return;
+	}
+
+	skb_reserve(skb, local->hw.extra_tx_headroom);
+	mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24);
+	memset(mgmt, 0, 24);
+	memcpy(mgmt->da, da, ETH_ALEN);
+	memcpy(mgmt->sa, dev->dev_addr, ETH_ALEN);
+	if (sdata->vif.type == IEEE80211_IF_TYPE_AP)
+		memcpy(mgmt->bssid, dev->dev_addr, ETH_ALEN);
+	else
+		memcpy(mgmt->bssid, ifsta->bssid, ETH_ALEN);
+	mgmt->frame_control = IEEE80211_FC(IEEE80211_FTYPE_MGMT,
+					IEEE80211_STYPE_ACTION);
+
+	skb_put(skb, 1 + sizeof(mgmt->u.action.u.delba));
+
+	mgmt->u.action.category = WLAN_CATEGORY_BACK;
+	mgmt->u.action.u.delba.action_code = WLAN_ACTION_DELBA;
+	params = (u16)(initiator << 11); 	/* bit 11 initiator */
+	params |= (u16)(tid << 12); 		/* bit 15:12 TID number */
+
+	mgmt->u.action.u.delba.params = cpu_to_le16(params);
+	mgmt->u.action.u.delba.reason_code = cpu_to_le16(reason_code);
+
+	ieee80211_sta_tx(dev, skb, 0);
+}
+
+void ieee80211_sta_stop_rx_ba_session(struct net_device *dev, u8 *ra, u16 tid,
+					u16 initiator, u16 reason)
+{
+	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+	struct ieee80211_hw *hw = &local->hw;
+	struct sta_info *sta;
+	int ret, i;
+
+	sta = sta_info_get(local, ra);
+	if (!sta)
+		return;
+
+	/* check if TID is in operational state */
+	spin_lock_bh(&sta->ampdu_mlme.ampdu_rx);
+	if (sta->ampdu_mlme.tid_rx[tid].state
+				!= HT_AGG_STATE_OPERATIONAL) {
+		spin_unlock_bh(&sta->ampdu_mlme.ampdu_rx);
+		sta_info_put(sta);
+		return;
+	}
+	sta->ampdu_mlme.tid_rx[tid].state =
+		HT_AGG_STATE_REQ_STOP_BA_MSK |
+		(initiator << HT_AGG_STATE_INITIATOR_SHIFT);
+		spin_unlock_bh(&sta->ampdu_mlme.ampdu_rx);
+
+	/* stop HW Rx aggregation. ampdu_action existence
+	 * already verified in session init so we add the BUG_ON */
+	BUG_ON(!local->ops->ampdu_action);
+
+	ret = local->ops->ampdu_action(hw, IEEE80211_AMPDU_RX_STOP,
+					ra, tid, NULL);
+	if (ret)
+		printk(KERN_DEBUG "HW problem - can not stop rx "
+				"aggergation for tid %d\n", tid);
+
+	/* shutdown timer has not expired */
+	if (initiator != WLAN_BACK_TIMER)
+		del_timer_sync(&sta->ampdu_mlme.tid_rx[tid].
+					session_timer);
+
+	/* check if this is a self generated aggregation halt */
+	if (initiator == WLAN_BACK_RECIPIENT || initiator == WLAN_BACK_TIMER)
+		ieee80211_send_delba(dev, ra, tid, 0, reason);
+
+	/* free the reordering buffer */
+	for (i = 0; i < sta->ampdu_mlme.tid_rx[tid].buf_size; i++) {
+		if (sta->ampdu_mlme.tid_rx[tid].reorder_buf[i]) {
+			/* release the reordered frames */
+			dev_kfree_skb(sta->ampdu_mlme.tid_rx[tid].reorder_buf[i]);
+			sta->ampdu_mlme.tid_rx[tid].stored_mpdu_num--;
+			sta->ampdu_mlme.tid_rx[tid].reorder_buf[i] = NULL;
+		}
+	}
+	kfree(sta->ampdu_mlme.tid_rx[tid].reorder_buf);
+
+	sta->ampdu_mlme.tid_rx[tid].state = HT_AGG_STATE_IDLE;
+	sta_info_put(sta);
+}
+
+
+static void ieee80211_sta_process_delba(struct net_device *dev,
+			struct ieee80211_mgmt *mgmt, size_t len)
+{
+	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+	struct sta_info *sta;
+	u16 tid, params;
+	u16 initiator;
+	DECLARE_MAC_BUF(mac);
+
+	sta = sta_info_get(local, mgmt->sa);
+	if (!sta)
+		return;
+
+	params = le16_to_cpu(mgmt->u.action.u.delba.params);
+	tid = (params & IEEE80211_DELBA_PARAM_TID_MASK) >> 12;
+	initiator = (params & IEEE80211_DELBA_PARAM_INITIATOR_MASK) >> 11;
+
+#ifdef CONFIG_MAC80211_HT_DEBUG
+	if (net_ratelimit())
+		printk(KERN_DEBUG "delba from %s (%s) tid %d reason code %d\n",
+			print_mac(mac, mgmt->sa),
+			initiator ? "recipient" : "initiator", tid,
+			mgmt->u.action.u.delba.reason_code);
+#endif /* CONFIG_MAC80211_HT_DEBUG */
+
+	if (initiator == WLAN_BACK_INITIATOR)
+		ieee80211_sta_stop_rx_ba_session(dev, sta->addr, tid,
+						 WLAN_BACK_INITIATOR, 0);
+	else { /* WLAN_BACK_RECIPIENT */
+		spin_lock_bh(&sta->ampdu_mlme.ampdu_tx);
+		sta->ampdu_mlme.tid_tx[tid].state =
+				HT_AGG_STATE_OPERATIONAL;
+		spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx);
+		ieee80211_stop_tx_ba_session(&local->hw, sta->addr, tid,
+					     WLAN_BACK_RECIPIENT);
+	}
+	sta_info_put(sta);
+}
+
+/*
+ * After sending add Block Ack request we activated a timer until
+ * add Block Ack response will arrive from the recipient.
+ * If this timer expires sta_addba_resp_timer_expired will be executed.
+ */
+void sta_addba_resp_timer_expired(unsigned long data)
+{
+	/* not an elegant detour, but there is no choice as the timer passes
+	 * only one argument, and both sta_info and TID are needed, so init
+	 * flow in sta_info_add gives the TID as data, while the timer_to_id
+	 * array gives the sta through container_of */
+	u16 tid = *(int *)data;
+	struct sta_info *temp_sta = container_of((void *)data,
+		struct sta_info, timer_to_tid[tid]);
+
+	struct ieee80211_local *local = temp_sta->local;
+	struct ieee80211_hw *hw = &local->hw;
+	struct sta_info *sta;
+	u8 *state;
+
+	sta = sta_info_get(local, temp_sta->addr);
+	if (!sta)
+		return;
+
+	state = &sta->ampdu_mlme.tid_tx[tid].state;
+	/* check if the TID waits for addBA response */
+	spin_lock_bh(&sta->ampdu_mlme.ampdu_tx);
+	if (!(*state & HT_ADDBA_REQUESTED_MSK)) {
+		spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx);
+		*state = HT_AGG_STATE_IDLE;
+		printk(KERN_DEBUG "timer expired on tid %d but we are not "
+				"expecting addBA response there", tid);
+		goto timer_expired_exit;
+	}
+
+	printk(KERN_DEBUG "addBA response timer expired on tid %d\n", tid);
+
+	/* go through the state check in stop_BA_session */
+	*state = HT_AGG_STATE_OPERATIONAL;
+	spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx);
+	ieee80211_stop_tx_ba_session(hw, temp_sta->addr, tid,
+				     WLAN_BACK_INITIATOR);
+
+timer_expired_exit:
+	sta_info_put(sta);
+}
+
+/*
+ * After receiving Block Ack Request (BAR) we activated a
+ * timer after each frame arrives from the originator.
+ * if this timer expires ieee80211_sta_stop_rx_ba_session will be executed.
+ */
+void sta_rx_agg_session_timer_expired(unsigned long data)
+{
+	/* not an elegant detour, but there is no choice as the timer passes
+	 * only one argument, and verious sta_info are needed here, so init
+	 * flow in sta_info_add gives the TID as data, while the timer_to_id
+	 * array gives the sta through container_of */
+	u8 *ptid = (u8 *)data;
+	u8 *timer_to_id = ptid - *ptid;
+	struct sta_info *sta = container_of(timer_to_id, struct sta_info,
+					 timer_to_tid[0]);
+
+	printk(KERN_DEBUG "rx session timer expired on tid %d\n", (u16)*ptid);
+	ieee80211_sta_stop_rx_ba_session(sta->dev, sta->addr, (u16)*ptid,
+					 WLAN_BACK_TIMER,
+					 WLAN_REASON_QSTA_TIMEOUT);
+}
+
 
 static void ieee80211_rx_mgmt_auth(struct net_device *dev,
 				   struct ieee80211_if_sta *ifsta,
@@ -943,37 +1508,38 @@ static void ieee80211_rx_mgmt_auth(struct net_device *dev,
 {
 	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
 	u16 auth_alg, auth_transaction, status_code;
+	DECLARE_MAC_BUF(mac);
 
 	if (ifsta->state != IEEE80211_AUTHENTICATE &&
-	    sdata->type != IEEE80211_IF_TYPE_IBSS) {
+	    sdata->vif.type != IEEE80211_IF_TYPE_IBSS) {
 		printk(KERN_DEBUG "%s: authentication frame received from "
-		       MAC_FMT ", but not in authenticate state - ignored\n",
-		       dev->name, MAC_ARG(mgmt->sa));
+		       "%s, but not in authenticate state - ignored\n",
+		       dev->name, print_mac(mac, mgmt->sa));
 		return;
 	}
 
 	if (len < 24 + 6) {
 		printk(KERN_DEBUG "%s: too short (%zd) authentication frame "
-		       "received from " MAC_FMT " - ignored\n",
-		       dev->name, len, MAC_ARG(mgmt->sa));
+		       "received from %s - ignored\n",
+		       dev->name, len, print_mac(mac, mgmt->sa));
 		return;
 	}
 
-	if (sdata->type != IEEE80211_IF_TYPE_IBSS &&
+	if (sdata->vif.type != IEEE80211_IF_TYPE_IBSS &&
 	    memcmp(ifsta->bssid, mgmt->sa, ETH_ALEN) != 0) {
 		printk(KERN_DEBUG "%s: authentication frame received from "
-		       "unknown AP (SA=" MAC_FMT " BSSID=" MAC_FMT ") - "
-		       "ignored\n", dev->name, MAC_ARG(mgmt->sa),
-		       MAC_ARG(mgmt->bssid));
+		       "unknown AP (SA=%s BSSID=%s) - "
+		       "ignored\n", dev->name, print_mac(mac, mgmt->sa),
+		       print_mac(mac, mgmt->bssid));
 		return;
 	}
 
-	if (sdata->type != IEEE80211_IF_TYPE_IBSS &&
+	if (sdata->vif.type != IEEE80211_IF_TYPE_IBSS &&
 	    memcmp(ifsta->bssid, mgmt->bssid, ETH_ALEN) != 0) {
 		printk(KERN_DEBUG "%s: authentication frame received from "
-		       "unknown BSSID (SA=" MAC_FMT " BSSID=" MAC_FMT ") - "
-		       "ignored\n", dev->name, MAC_ARG(mgmt->sa),
-		       MAC_ARG(mgmt->bssid));
+		       "unknown BSSID (SA=%s BSSID=%s) - "
+		       "ignored\n", dev->name, print_mac(mac, mgmt->sa),
+		       print_mac(mac, mgmt->bssid));
 		return;
 	}
 
@@ -981,12 +1547,12 @@ static void ieee80211_rx_mgmt_auth(struct net_device *dev,
 	auth_transaction = le16_to_cpu(mgmt->u.auth.auth_transaction);
 	status_code = le16_to_cpu(mgmt->u.auth.status_code);
 
-	printk(KERN_DEBUG "%s: RX authentication from " MAC_FMT " (alg=%d "
+	printk(KERN_DEBUG "%s: RX authentication from %s (alg=%d "
 	       "transaction=%d status=%d)\n",
-	       dev->name, MAC_ARG(mgmt->sa), auth_alg,
+	       dev->name, print_mac(mac, mgmt->sa), auth_alg,
 	       auth_transaction, status_code);
 
-	if (sdata->type == IEEE80211_IF_TYPE_IBSS) {
+	if (sdata->vif.type == IEEE80211_IF_TYPE_IBSS) {
 		/* IEEE 802.11 standard does not require authentication in IBSS
 		 * networks and most implementations do not seem to use it.
 		 * However, try to reply to authentication attempts if someone
@@ -1070,27 +1636,28 @@ static void ieee80211_rx_mgmt_deauth(struct net_device *dev,
 				     size_t len)
 {
 	u16 reason_code;
+	DECLARE_MAC_BUF(mac);
 
 	if (len < 24 + 2) {
 		printk(KERN_DEBUG "%s: too short (%zd) deauthentication frame "
-		       "received from " MAC_FMT " - ignored\n",
-		       dev->name, len, MAC_ARG(mgmt->sa));
+		       "received from %s - ignored\n",
+		       dev->name, len, print_mac(mac, mgmt->sa));
 		return;
 	}
 
 	if (memcmp(ifsta->bssid, mgmt->sa, ETH_ALEN) != 0) {
 		printk(KERN_DEBUG "%s: deauthentication frame received from "
-		       "unknown AP (SA=" MAC_FMT " BSSID=" MAC_FMT ") - "
-		       "ignored\n", dev->name, MAC_ARG(mgmt->sa),
-		       MAC_ARG(mgmt->bssid));
+		       "unknown AP (SA=%s BSSID=%s) - "
+		       "ignored\n", dev->name, print_mac(mac, mgmt->sa),
+		       print_mac(mac, mgmt->bssid));
 		return;
 	}
 
 	reason_code = le16_to_cpu(mgmt->u.deauth.reason_code);
 
-	printk(KERN_DEBUG "%s: RX deauthentication from " MAC_FMT
+	printk(KERN_DEBUG "%s: RX deauthentication from %s"
 	       " (reason=%d)\n",
-	       dev->name, MAC_ARG(mgmt->sa), reason_code);
+	       dev->name, print_mac(mac, mgmt->sa), reason_code);
 
 	if (ifsta->flags & IEEE80211_STA_AUTHENTICATED) {
 		printk(KERN_DEBUG "%s: deauthenticated\n", dev->name);
@@ -1115,27 +1682,28 @@ static void ieee80211_rx_mgmt_disassoc(struct net_device *dev,
 				       size_t len)
 {
 	u16 reason_code;
+	DECLARE_MAC_BUF(mac);
 
 	if (len < 24 + 2) {
 		printk(KERN_DEBUG "%s: too short (%zd) disassociation frame "
-		       "received from " MAC_FMT " - ignored\n",
-		       dev->name, len, MAC_ARG(mgmt->sa));
+		       "received from %s - ignored\n",
+		       dev->name, len, print_mac(mac, mgmt->sa));
 		return;
 	}
 
 	if (memcmp(ifsta->bssid, mgmt->sa, ETH_ALEN) != 0) {
 		printk(KERN_DEBUG "%s: disassociation frame received from "
-		       "unknown AP (SA=" MAC_FMT " BSSID=" MAC_FMT ") - "
-		       "ignored\n", dev->name, MAC_ARG(mgmt->sa),
-		       MAC_ARG(mgmt->bssid));
+		       "unknown AP (SA=%s BSSID=%s) - "
+		       "ignored\n", dev->name, print_mac(mac, mgmt->sa),
+		       print_mac(mac, mgmt->bssid));
 		return;
 	}
 
 	reason_code = le16_to_cpu(mgmt->u.disassoc.reason_code);
 
-	printk(KERN_DEBUG "%s: RX disassociation from " MAC_FMT
+	printk(KERN_DEBUG "%s: RX disassociation from %s"
 	       " (reason=%d)\n",
-	       dev->name, MAC_ARG(mgmt->sa), reason_code);
+	       dev->name, print_mac(mac, mgmt->sa), reason_code);
 
 	if (ifsta->flags & IEEE80211_STA_ASSOCIATED)
 		printk(KERN_DEBUG "%s: disassociated\n", dev->name);
@@ -1150,58 +1718,58 @@ static void ieee80211_rx_mgmt_disassoc(struct net_device *dev,
 }
 
 
-static void ieee80211_rx_mgmt_assoc_resp(struct net_device *dev,
+static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata,
 					 struct ieee80211_if_sta *ifsta,
 					 struct ieee80211_mgmt *mgmt,
 					 size_t len,
 					 int reassoc)
 {
-	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
-	struct ieee80211_hw_mode *mode;
+	struct ieee80211_local *local = sdata->local;
+	struct net_device *dev = sdata->dev;
+	struct ieee80211_supported_band *sband;
 	struct sta_info *sta;
-	u32 rates;
+	u64 rates, basic_rates;
 	u16 capab_info, status_code, aid;
 	struct ieee802_11_elems elems;
+	struct ieee80211_bss_conf *bss_conf = &sdata->bss_conf;
 	u8 *pos;
 	int i, j;
+	DECLARE_MAC_BUF(mac);
+	bool have_higher_than_11mbit = false;
 
 	/* AssocResp and ReassocResp have identical structure, so process both
 	 * of them in this function. */
 
 	if (ifsta->state != IEEE80211_ASSOCIATE) {
 		printk(KERN_DEBUG "%s: association frame received from "
-		       MAC_FMT ", but not in associate state - ignored\n",
-		       dev->name, MAC_ARG(mgmt->sa));
+		       "%s, but not in associate state - ignored\n",
+		       dev->name, print_mac(mac, mgmt->sa));
 		return;
 	}
 
 	if (len < 24 + 6) {
 		printk(KERN_DEBUG "%s: too short (%zd) association frame "
-		       "received from " MAC_FMT " - ignored\n",
-		       dev->name, len, MAC_ARG(mgmt->sa));
+		       "received from %s - ignored\n",
+		       dev->name, len, print_mac(mac, mgmt->sa));
 		return;
 	}
 
 	if (memcmp(ifsta->bssid, mgmt->sa, ETH_ALEN) != 0) {
 		printk(KERN_DEBUG "%s: association frame received from "
-		       "unknown AP (SA=" MAC_FMT " BSSID=" MAC_FMT ") - "
-		       "ignored\n", dev->name, MAC_ARG(mgmt->sa),
-		       MAC_ARG(mgmt->bssid));
+		       "unknown AP (SA=%s BSSID=%s) - "
+		       "ignored\n", dev->name, print_mac(mac, mgmt->sa),
+		       print_mac(mac, mgmt->bssid));
 		return;
 	}
 
 	capab_info = le16_to_cpu(mgmt->u.assoc_resp.capab_info);
 	status_code = le16_to_cpu(mgmt->u.assoc_resp.status_code);
 	aid = le16_to_cpu(mgmt->u.assoc_resp.aid);
-	if ((aid & (BIT(15) | BIT(14))) != (BIT(15) | BIT(14)))
-		printk(KERN_DEBUG "%s: invalid aid value %d; bits 15:14 not "
-		       "set\n", dev->name, aid);
-	aid &= ~(BIT(15) | BIT(14));
 
-	printk(KERN_DEBUG "%s: RX %sssocResp from " MAC_FMT " (capab=0x%x "
+	printk(KERN_DEBUG "%s: RX %sssocResp from %s (capab=0x%x "
 	       "status=%d aid=%d)\n",
-	       dev->name, reassoc ? "Rea" : "A", MAC_ARG(mgmt->sa),
-	       capab_info, status_code, aid);
+	       dev->name, reassoc ? "Rea" : "A", print_mac(mac, mgmt->sa),
+	       capab_info, status_code, (u16)(aid & ~(BIT(15) | BIT(14))));
 
 	if (status_code != WLAN_STATUS_SUCCESS) {
 		printk(KERN_DEBUG "%s: AP denied association (code=%d)\n",
@@ -1213,13 +1781,13 @@ static void ieee80211_rx_mgmt_assoc_resp(struct net_device *dev,
 		return;
 	}
 
+	if ((aid & (BIT(15) | BIT(14))) != (BIT(15) | BIT(14)))
+		printk(KERN_DEBUG "%s: invalid aid value %d; bits 15:14 not "
+		       "set\n", dev->name, aid);
+	aid &= ~(BIT(15) | BIT(14));
+
 	pos = mgmt->u.assoc_resp.variable;
-	if (ieee802_11_parse_elems(pos, len - (pos - (u8 *) mgmt), &elems)
-	    == ParseFailed) {
-		printk(KERN_DEBUG "%s: failed to parse AssocResp\n",
-		       dev->name);
-		return;
-	}
+	ieee802_11_parse_elems(pos, len - (pos - (u8 *) mgmt), &elems);
 
 	if (!elems.supp_rates) {
 		printk(KERN_DEBUG "%s: no SuppRates element in AssocResp\n",
@@ -1227,18 +1795,6 @@ static void ieee80211_rx_mgmt_assoc_resp(struct net_device *dev,
 		return;
 	}
 
-	/* it probably doesn't, but if the frame includes an ERP value then
-	 * update our stored copy */
-	if (elems.erp_info && elems.erp_info_len >= 1) {
-		struct ieee80211_sta_bss *bss
-			= ieee80211_rx_bss_get(dev, ifsta->bssid);
-		if (bss) {
-			bss->erp_value = elems.erp_info[0];
-			bss->has_erp_value = 1;
-			ieee80211_rx_bss_put(dev, bss);
-		}
-	}
-
 	printk(KERN_DEBUG "%s: associated\n", dev->name);
 	ifsta->aid = aid;
 	ifsta->ap_capab = capab_info;
@@ -1249,8 +1805,6 @@ static void ieee80211_rx_mgmt_assoc_resp(struct net_device *dev,
 	if (ifsta->assocresp_ies)
 		memcpy(ifsta->assocresp_ies, pos, ifsta->assocresp_ies_len);
 
-	ieee80211_set_associated(dev, ifsta, 1);
-
 	/* Add STA entry for the AP */
 	sta = sta_info_get(local, ifsta->bssid);
 	if (!sta) {
@@ -1261,7 +1815,9 @@ static void ieee80211_rx_mgmt_assoc_resp(struct net_device *dev,
 			       " AP\n", dev->name);
 			return;
 		}
-		bss = ieee80211_rx_bss_get(dev, ifsta->bssid);
+		bss = ieee80211_rx_bss_get(dev, ifsta->bssid,
+					   local->hw.conf.channel->center_freq,
+					   ifsta->ssid, ifsta->ssid_len);
 		if (bss) {
 			sta->last_rssi = bss->rssi;
 			sta->last_signal = bss->signal;
@@ -1271,23 +1827,63 @@ static void ieee80211_rx_mgmt_assoc_resp(struct net_device *dev,
 	}
 
 	sta->dev = dev;
-	sta->flags |= WLAN_STA_AUTH | WLAN_STA_ASSOC | WLAN_STA_ASSOC_AP;
+	sta->flags |= WLAN_STA_AUTH | WLAN_STA_ASSOC | WLAN_STA_ASSOC_AP |
+		      WLAN_STA_AUTHORIZED;
 
 	rates = 0;
-	mode = local->oper_hw_mode;
+	basic_rates = 0;
+	sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
+
 	for (i = 0; i < elems.supp_rates_len; i++) {
 		int rate = (elems.supp_rates[i] & 0x7f) * 5;
-		for (j = 0; j < mode->num_rates; j++)
-			if (mode->rates[j].rate == rate)
+
+		if (rate > 110)
+			have_higher_than_11mbit = true;
+
+		for (j = 0; j < sband->n_bitrates; j++) {
+			if (sband->bitrates[j].bitrate == rate)
 				rates |= BIT(j);
+			if (elems.supp_rates[i] & 0x80)
+				basic_rates |= BIT(j);
+		}
 	}
+
 	for (i = 0; i < elems.ext_supp_rates_len; i++) {
 		int rate = (elems.ext_supp_rates[i] & 0x7f) * 5;
-		for (j = 0; j < mode->num_rates; j++)
-			if (mode->rates[j].rate == rate)
+
+		if (rate > 110)
+			have_higher_than_11mbit = true;
+
+		for (j = 0; j < sband->n_bitrates; j++) {
+			if (sband->bitrates[j].bitrate == rate)
 				rates |= BIT(j);
+			if (elems.ext_supp_rates[i] & 0x80)
+				basic_rates |= BIT(j);
+		}
+	}
+
+	sta->supp_rates[local->hw.conf.channel->band] = rates;
+	sdata->basic_rates = basic_rates;
+
+	/* cf. IEEE 802.11 9.2.12 */
+	if (local->hw.conf.channel->band == IEEE80211_BAND_2GHZ &&
+	    have_higher_than_11mbit)
+		sdata->flags |= IEEE80211_SDATA_OPERATING_GMODE;
+	else
+		sdata->flags &= ~IEEE80211_SDATA_OPERATING_GMODE;
+
+	if (elems.ht_cap_elem && elems.ht_info_elem && elems.wmm_param &&
+	    local->ops->conf_ht) {
+		struct ieee80211_ht_bss_info bss_info;
+
+		ieee80211_ht_cap_ie_to_ht_info(
+				(struct ieee80211_ht_cap *)
+				elems.ht_cap_elem, &sta->ht_info);
+		ieee80211_ht_addt_info_ie_to_ht_bss_info(
+				(struct ieee80211_ht_addt_info *)
+				elems.ht_info_elem, &bss_info);
+		ieee80211_hw_config_ht(local, 1, &sta->ht_info, &bss_info);
 	}
-	sta->supp_rates = rates;
 
 	rate_control_rate_init(sta, local);
 
@@ -1297,6 +1893,9 @@ static void ieee80211_rx_mgmt_assoc_resp(struct net_device *dev,
 					 elems.wmm_param_len);
 	}
 
+	/* set AID, ieee80211_set_associated() will tell the driver */
+	bss_conf->aid = aid;
+	ieee80211_set_associated(dev, ifsta, 1);
 
 	sta_info_put(sta);
 
@@ -1337,7 +1936,8 @@ static void __ieee80211_rx_bss_hash_del(struct net_device *dev,
 
 
 static struct ieee80211_sta_bss *
-ieee80211_rx_bss_add(struct net_device *dev, u8 *bssid)
+ieee80211_rx_bss_add(struct net_device *dev, u8 *bssid, int freq,
+		     u8 *ssid, u8 ssid_len)
 {
 	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
 	struct ieee80211_sta_bss *bss;
@@ -1348,6 +1948,11 @@ ieee80211_rx_bss_add(struct net_device *dev, u8 *bssid)
 	atomic_inc(&bss->users);
 	atomic_inc(&bss->users);
 	memcpy(bss->bssid, bssid, ETH_ALEN);
+	bss->freq = freq;
+	if (ssid && ssid_len <= IEEE80211_MAX_SSID_LEN) {
+		memcpy(bss->ssid, ssid, ssid_len);
+		bss->ssid_len = ssid_len;
+	}
 
 	spin_lock_bh(&local->sta_bss_lock);
 	/* TODO: order by RSSI? */
@@ -1359,7 +1964,8 @@ ieee80211_rx_bss_add(struct net_device *dev, u8 *bssid)
 
 
 static struct ieee80211_sta_bss *
-ieee80211_rx_bss_get(struct net_device *dev, u8 *bssid)
+ieee80211_rx_bss_get(struct net_device *dev, u8 *bssid, int freq,
+		     u8 *ssid, u8 ssid_len)
 {
 	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
 	struct ieee80211_sta_bss *bss;
@@ -1367,7 +1973,10 @@ ieee80211_rx_bss_get(struct net_device *dev, u8 *bssid)
 	spin_lock_bh(&local->sta_bss_lock);
 	bss = local->sta_bss_hash[STA_HASH(bssid)];
 	while (bss) {
-		if (memcmp(bss->bssid, bssid, ETH_ALEN) == 0) {
+		if (!memcmp(bss->bssid, bssid, ETH_ALEN) &&
+		    bss->freq == freq &&
+		    bss->ssid_len == ssid_len &&
+		    (ssid_len == 0 || !memcmp(bss->ssid, ssid, ssid_len))) {
 			atomic_inc(&bss->users);
 			break;
 		}
@@ -1383,6 +1992,7 @@ static void ieee80211_rx_bss_free(struct ieee80211_sta_bss *bss)
 	kfree(bss->wpa_ie);
 	kfree(bss->rsn_ie);
 	kfree(bss->wmm_ie);
+	kfree(bss->ht_ie);
 	kfree(bss);
 }
 
@@ -1429,19 +2039,21 @@ static void ieee80211_rx_bss_info(struct net_device *dev,
 	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
 	struct ieee802_11_elems elems;
 	size_t baselen;
-	int channel, invalid = 0, clen;
+	int freq, clen;
 	struct ieee80211_sta_bss *bss;
 	struct sta_info *sta;
 	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
 	u64 timestamp;
+	DECLARE_MAC_BUF(mac);
+	DECLARE_MAC_BUF(mac2);
 
 	if (!beacon && memcmp(mgmt->da, dev->dev_addr, ETH_ALEN))
 		return; /* ignore ProbeResp to foreign address */
 
 #if 0
-	printk(KERN_DEBUG "%s: RX %s from " MAC_FMT " to " MAC_FMT "\n",
+	printk(KERN_DEBUG "%s: RX %s from %s to %s\n",
 	       dev->name, beacon ? "Beacon" : "Probe Response",
-	       MAC_ARG(mgmt->sa), MAC_ARG(mgmt->da));
+	       print_mac(mac, mgmt->sa), print_mac(mac2, mgmt->da));
 #endif
 
 	baselen = (u8 *) mgmt->u.beacon.variable - (u8 *) mgmt;
@@ -1450,7 +2062,7 @@ static void ieee80211_rx_bss_info(struct net_device *dev,
 
 	timestamp = le64_to_cpu(mgmt->u.beacon.timestamp);
 
-	if (sdata->type == IEEE80211_IF_TYPE_IBSS && beacon &&
+	if (sdata->vif.type == IEEE80211_IF_TYPE_IBSS && beacon &&
 	    memcmp(mgmt->bssid, sdata->u.sta.bssid, ETH_ALEN) == 0) {
 #ifdef CONFIG_MAC80211_IBSS_DEBUG
 		static unsigned long last_tsf_debug = 0;
@@ -1460,10 +2072,10 @@ static void ieee80211_rx_bss_info(struct net_device *dev,
 		else
 			tsf = -1LLU;
 		if (time_after(jiffies, last_tsf_debug + 5 * HZ)) {
-			printk(KERN_DEBUG "RX beacon SA=" MAC_FMT " BSSID="
-			       MAC_FMT " TSF=0x%llx BCN=0x%llx diff=%lld "
+			printk(KERN_DEBUG "RX beacon SA=%s BSSID="
+			       "%s TSF=0x%llx BCN=0x%llx diff=%lld "
 			       "@%lu\n",
-			       MAC_ARG(mgmt->sa), MAC_ARG(mgmt->bssid),
+			       print_mac(mac, mgmt->sa), print_mac(mac2, mgmt->bssid),
 			       (unsigned long long)tsf,
 			       (unsigned long long)timestamp,
 			       (unsigned long long)(tsf - timestamp),
@@ -1473,23 +2085,27 @@ static void ieee80211_rx_bss_info(struct net_device *dev,
 #endif /* CONFIG_MAC80211_IBSS_DEBUG */
 	}
 
-	if (ieee802_11_parse_elems(mgmt->u.beacon.variable, len - baselen,
-				   &elems) == ParseFailed)
-		invalid = 1;
+	ieee802_11_parse_elems(mgmt->u.beacon.variable, len - baselen, &elems);
 
-	if (sdata->type == IEEE80211_IF_TYPE_IBSS && elems.supp_rates &&
+	if (sdata->vif.type == IEEE80211_IF_TYPE_IBSS && elems.supp_rates &&
 	    memcmp(mgmt->bssid, sdata->u.sta.bssid, ETH_ALEN) == 0 &&
 	    (sta = sta_info_get(local, mgmt->sa))) {
-		struct ieee80211_hw_mode *mode;
-		struct ieee80211_rate *rates;
+		struct ieee80211_supported_band *sband;
+		struct ieee80211_rate *bitrates;
 		size_t num_rates;
-		u32 supp_rates, prev_rates;
+		u64 supp_rates, prev_rates;
 		int i, j;
 
-		mode = local->sta_scanning ?
-		       local->scan_hw_mode : local->oper_hw_mode;
-		rates = mode->rates;
-		num_rates = mode->num_rates;
+		sband = local->hw.wiphy->bands[rx_status->band];
+
+		if (!sband) {
+			WARN_ON(1);
+			sband = local->hw.wiphy->bands[
+					local->hw.conf.channel->band];
+		}
+
+		bitrates = sband->bitrates;
+		num_rates = sband->n_bitrates;
 
 		supp_rates = 0;
 		for (i = 0; i < elems.supp_rates_len +
@@ -1503,24 +2119,27 @@ static void ieee80211_rx_bss_info(struct net_device *dev,
 					[i - elems.supp_rates_len];
 			own_rate = 5 * (rate & 0x7f);
 			for (j = 0; j < num_rates; j++)
-				if (rates[j].rate == own_rate)
+				if (bitrates[j].bitrate == own_rate)
 					supp_rates |= BIT(j);
 		}
 
-		prev_rates = sta->supp_rates;
-		sta->supp_rates &= supp_rates;
-		if (sta->supp_rates == 0) {
+		prev_rates = sta->supp_rates[rx_status->band];
+		sta->supp_rates[rx_status->band] &= supp_rates;
+		if (sta->supp_rates[rx_status->band] == 0) {
 			/* No matching rates - this should not really happen.
 			 * Make sure that at least one rate is marked
 			 * supported to avoid issues with TX rate ctrl. */
-			sta->supp_rates = sdata->u.sta.supp_rates_bits;
+			sta->supp_rates[rx_status->band] =
+				sdata->u.sta.supp_rates_bits[rx_status->band];
 		}
-		if (sta->supp_rates != prev_rates) {
+		if (sta->supp_rates[rx_status->band] != prev_rates) {
 			printk(KERN_DEBUG "%s: updated supp_rates set for "
-			       MAC_FMT " based on beacon info (0x%x & 0x%x -> "
-			       "0x%x)\n",
-			       dev->name, MAC_ARG(sta->addr), prev_rates,
-			       supp_rates, sta->supp_rates);
+			       "%s based on beacon info (0x%llx & 0x%llx -> "
+			       "0x%llx)\n",
+			       dev->name, print_mac(mac, sta->addr),
+			       (unsigned long long) prev_rates,
+			       (unsigned long long) supp_rates,
+			       (unsigned long long) sta->supp_rates[rx_status->band]);
 		}
 		sta_info_put(sta);
 	}
@@ -1529,13 +2148,15 @@ static void ieee80211_rx_bss_info(struct net_device *dev,
 		return;
 
 	if (elems.ds_params && elems.ds_params_len == 1)
-		channel = elems.ds_params[0];
+		freq = ieee80211_channel_to_frequency(elems.ds_params[0]);
 	else
-		channel = rx_status->channel;
+		freq = rx_status->freq;
 
-	bss = ieee80211_rx_bss_get(dev, mgmt->bssid);
+	bss = ieee80211_rx_bss_get(dev, mgmt->bssid, freq,
+				   elems.ssid, elems.ssid_len);
 	if (!bss) {
-		bss = ieee80211_rx_bss_add(dev, mgmt->bssid);
+		bss = ieee80211_rx_bss_add(dev, mgmt->bssid, freq,
+					   elems.ssid, elems.ssid_len);
 		if (!bss)
 			return;
 	} else {
@@ -1547,6 +2168,8 @@ static void ieee80211_rx_bss_info(struct net_device *dev,
 #endif
 	}
 
+	bss->band = rx_status->band;
+
 	if (bss->probe_resp && beacon) {
 		/* Do not allow beacon to override data from Probe Response. */
 		ieee80211_rx_bss_put(dev, bss);
@@ -1561,10 +2184,6 @@ static void ieee80211_rx_bss_info(struct net_device *dev,
 
 	bss->beacon_int = le16_to_cpu(mgmt->u.beacon.beacon_int);
 	bss->capability = le16_to_cpu(mgmt->u.beacon.capab_info);
-	if (elems.ssid && elems.ssid_len <= IEEE80211_MAX_SSID_LEN) {
-		memcpy(bss->ssid, elems.ssid, elems.ssid_len);
-		bss->ssid_len = elems.ssid_len;
-	}
 
 	bss->supp_rates_len = 0;
 	if (elems.supp_rates) {
@@ -1632,23 +2251,23 @@ static void ieee80211_rx_bss_info(struct net_device *dev,
 		bss->wmm_ie = NULL;
 		bss->wmm_ie_len = 0;
 	}
-
-
-	bss->hw_mode = rx_status->phymode;
-	bss->channel = channel;
-	bss->freq = rx_status->freq;
-	if (channel != rx_status->channel &&
-	    (bss->hw_mode == MODE_IEEE80211G ||
-	     bss->hw_mode == MODE_IEEE80211B) &&
-	    channel >= 1 && channel <= 14) {
-		static const int freq_list[] = {
-			2412, 2417, 2422, 2427, 2432, 2437, 2442,
-			2447, 2452, 2457, 2462, 2467, 2472, 2484
-		};
-		/* IEEE 802.11g/b mode can receive packets from neighboring
-		 * channels, so map the channel into frequency. */
-		bss->freq = freq_list[channel - 1];
+	if (elems.ht_cap_elem &&
+	    (!bss->ht_ie || bss->ht_ie_len != elems.ht_cap_elem_len ||
+	     memcmp(bss->ht_ie, elems.ht_cap_elem, elems.ht_cap_elem_len))) {
+		kfree(bss->ht_ie);
+		bss->ht_ie = kmalloc(elems.ht_cap_elem_len + 2, GFP_ATOMIC);
+		if (bss->ht_ie) {
+			memcpy(bss->ht_ie, elems.ht_cap_elem - 2,
+			       elems.ht_cap_elem_len + 2);
+			bss->ht_ie_len = elems.ht_cap_elem_len + 2;
+		} else
+			bss->ht_ie_len = 0;
+	} else if (!elems.ht_cap_elem && bss->ht_ie) {
+		kfree(bss->ht_ie);
+		bss->ht_ie = NULL;
+		bss->ht_ie_len = 0;
 	}
+
 	bss->timestamp = timestamp;
 	bss->last_update = jiffies;
 	bss->rssi = rx_status->ssi;
@@ -1678,11 +2297,14 @@ static void ieee80211_rx_mgmt_beacon(struct net_device *dev,
 	struct ieee80211_if_sta *ifsta;
 	size_t baselen;
 	struct ieee802_11_elems elems;
+	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+	struct ieee80211_conf *conf = &local->hw.conf;
+	u32 changed = 0;
 
 	ieee80211_rx_bss_info(dev, mgmt, len, rx_status, 1);
 
 	sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-	if (sdata->type != IEEE80211_IF_TYPE_STA)
+	if (sdata->vif.type != IEEE80211_IF_TYPE_STA)
 		return;
 	ifsta = &sdata->u.sta;
 
@@ -1695,17 +2317,34 @@ static void ieee80211_rx_mgmt_beacon(struct net_device *dev,
 	if (baselen > len)
 		return;
 
-	if (ieee802_11_parse_elems(mgmt->u.beacon.variable, len - baselen,
-				   &elems) == ParseFailed)
-		return;
+	ieee802_11_parse_elems(mgmt->u.beacon.variable, len - baselen, &elems);
 
 	if (elems.erp_info && elems.erp_info_len >= 1)
-		ieee80211_handle_erp_ie(dev, elems.erp_info[0]);
+		changed |= ieee80211_handle_erp_ie(sdata, elems.erp_info[0]);
+
+	if (elems.ht_cap_elem && elems.ht_info_elem &&
+	    elems.wmm_param && local->ops->conf_ht &&
+	    conf->flags & IEEE80211_CONF_SUPPORT_HT_MODE) {
+		struct ieee80211_ht_bss_info bss_info;
+
+		ieee80211_ht_addt_info_ie_to_ht_bss_info(
+				(struct ieee80211_ht_addt_info *)
+				elems.ht_info_elem, &bss_info);
+		/* check if AP changed bss inforamation */
+		if ((conf->ht_bss_conf.primary_channel !=
+		     bss_info.primary_channel) ||
+		    (conf->ht_bss_conf.bss_cap != bss_info.bss_cap) ||
+		    (conf->ht_bss_conf.bss_op_mode != bss_info.bss_op_mode))
+			ieee80211_hw_config_ht(local, 1, &conf->ht_conf,
+						&bss_info);
+	}
 
 	if (elems.wmm_param && (ifsta->flags & IEEE80211_STA_WMM_ENABLED)) {
 		ieee80211_sta_wmm_params(dev, ifsta, elems.wmm_param,
 					 elems.wmm_param_len);
 	}
+
+	ieee80211_bss_info_change_notify(sdata, changed);
 }
 
 
@@ -1721,8 +2360,13 @@ static void ieee80211_rx_mgmt_probe_req(struct net_device *dev,
 	struct sk_buff *skb;
 	struct ieee80211_mgmt *resp;
 	u8 *pos, *end;
+	DECLARE_MAC_BUF(mac);
+#ifdef CONFIG_MAC80211_IBSS_DEBUG
+	DECLARE_MAC_BUF(mac2);
+	DECLARE_MAC_BUF(mac3);
+#endif
 
-	if (sdata->type != IEEE80211_IF_TYPE_IBSS ||
+	if (sdata->vif.type != IEEE80211_IF_TYPE_IBSS ||
 	    ifsta->state != IEEE80211_IBSS_JOINED ||
 	    len < 24 + 2 || !ifsta->probe_resp)
 		return;
@@ -1733,10 +2377,10 @@ static void ieee80211_rx_mgmt_probe_req(struct net_device *dev,
 		tx_last_beacon = 1;
 
 #ifdef CONFIG_MAC80211_IBSS_DEBUG
-	printk(KERN_DEBUG "%s: RX ProbeReq SA=" MAC_FMT " DA=" MAC_FMT " BSSID="
-	       MAC_FMT " (tx_last_beacon=%d)\n",
-	       dev->name, MAC_ARG(mgmt->sa), MAC_ARG(mgmt->da),
-	       MAC_ARG(mgmt->bssid), tx_last_beacon);
+	printk(KERN_DEBUG "%s: RX ProbeReq SA=%s DA=%s BSSID="
+	       "%s (tx_last_beacon=%d)\n",
+	       dev->name, print_mac(mac, mgmt->sa), print_mac(mac2, mgmt->da),
+	       print_mac(mac3, mgmt->bssid), tx_last_beacon);
 #endif /* CONFIG_MAC80211_IBSS_DEBUG */
 
 	if (!tx_last_beacon)
@@ -1752,8 +2396,8 @@ static void ieee80211_rx_mgmt_probe_req(struct net_device *dev,
 	    pos + 2 + pos[1] > end) {
 		if (net_ratelimit()) {
 			printk(KERN_DEBUG "%s: Invalid SSID IE in ProbeReq "
-			       "from " MAC_FMT "\n",
-			       dev->name, MAC_ARG(mgmt->sa));
+			       "from %s\n",
+			       dev->name, print_mac(mac, mgmt->sa));
 		}
 		return;
 	}
@@ -1772,12 +2416,52 @@ static void ieee80211_rx_mgmt_probe_req(struct net_device *dev,
 	resp = (struct ieee80211_mgmt *) skb->data;
 	memcpy(resp->da, mgmt->sa, ETH_ALEN);
 #ifdef CONFIG_MAC80211_IBSS_DEBUG
-	printk(KERN_DEBUG "%s: Sending ProbeResp to " MAC_FMT "\n",
-	       dev->name, MAC_ARG(resp->da));
+	printk(KERN_DEBUG "%s: Sending ProbeResp to %s\n",
+	       dev->name, print_mac(mac, resp->da));
 #endif /* CONFIG_MAC80211_IBSS_DEBUG */
 	ieee80211_sta_tx(dev, skb, 0);
 }
 
+static void ieee80211_rx_mgmt_action(struct net_device *dev,
+				     struct ieee80211_if_sta *ifsta,
+				     struct ieee80211_mgmt *mgmt,
+				     size_t len)
+{
+	if (len < IEEE80211_MIN_ACTION_SIZE)
+		return;
+
+	switch (mgmt->u.action.category) {
+	case WLAN_CATEGORY_BACK:
+		switch (mgmt->u.action.u.addba_req.action_code) {
+		case WLAN_ACTION_ADDBA_REQ:
+			if (len < (IEEE80211_MIN_ACTION_SIZE +
+				   sizeof(mgmt->u.action.u.addba_req)))
+				break;
+			ieee80211_sta_process_addba_request(dev, mgmt, len);
+			break;
+		case WLAN_ACTION_ADDBA_RESP:
+			if (len < (IEEE80211_MIN_ACTION_SIZE +
+				   sizeof(mgmt->u.action.u.addba_resp)))
+				break;
+			ieee80211_sta_process_addba_resp(dev, mgmt, len);
+			break;
+		case WLAN_ACTION_DELBA:
+			if (len < (IEEE80211_MIN_ACTION_SIZE +
+				   sizeof(mgmt->u.action.u.delba)))
+				break;
+			ieee80211_sta_process_delba(dev, mgmt, len);
+			break;
+		default:
+			if (net_ratelimit())
+			   printk(KERN_DEBUG "%s: Rx unknown A-MPDU action\n",
+					dev->name);
+			break;
+		}
+		break;
+	default:
+		break;
+	}
+}
 
 void ieee80211_sta_rx_mgmt(struct net_device *dev, struct sk_buff *skb,
 			   struct ieee80211_rx_status *rx_status)
@@ -1807,6 +2491,7 @@ void ieee80211_sta_rx_mgmt(struct net_device *dev, struct sk_buff *skb,
 	case IEEE80211_STYPE_REASSOC_RESP:
 	case IEEE80211_STYPE_DEAUTH:
 	case IEEE80211_STYPE_DISASSOC:
+	case IEEE80211_STYPE_ACTION:
 		skb_queue_tail(&ifsta->skb_queue, skb);
 		queue_work(local->hw.workqueue, &ifsta->work);
 		return;
@@ -1853,10 +2538,10 @@ static void ieee80211_sta_rx_queued_mgmt(struct net_device *dev,
 		ieee80211_rx_mgmt_auth(dev, ifsta, mgmt, skb->len);
 		break;
 	case IEEE80211_STYPE_ASSOC_RESP:
-		ieee80211_rx_mgmt_assoc_resp(dev, ifsta, mgmt, skb->len, 0);
+		ieee80211_rx_mgmt_assoc_resp(sdata, ifsta, mgmt, skb->len, 0);
 		break;
 	case IEEE80211_STYPE_REASSOC_RESP:
-		ieee80211_rx_mgmt_assoc_resp(dev, ifsta, mgmt, skb->len, 1);
+		ieee80211_rx_mgmt_assoc_resp(sdata, ifsta, mgmt, skb->len, 1);
 		break;
 	case IEEE80211_STYPE_DEAUTH:
 		ieee80211_rx_mgmt_deauth(dev, ifsta, mgmt, skb->len);
@@ -1864,37 +2549,48 @@ static void ieee80211_sta_rx_queued_mgmt(struct net_device *dev,
 	case IEEE80211_STYPE_DISASSOC:
 		ieee80211_rx_mgmt_disassoc(dev, ifsta, mgmt, skb->len);
 		break;
+	case IEEE80211_STYPE_ACTION:
+		ieee80211_rx_mgmt_action(dev, ifsta, mgmt, skb->len);
+		break;
 	}
 
 	kfree_skb(skb);
 }
 
 
-void ieee80211_sta_rx_scan(struct net_device *dev, struct sk_buff *skb,
-			   struct ieee80211_rx_status *rx_status)
+ieee80211_rx_result
+ieee80211_sta_rx_scan(struct net_device *dev, struct sk_buff *skb,
+		      struct ieee80211_rx_status *rx_status)
 {
 	struct ieee80211_mgmt *mgmt;
 	u16 fc;
 
-	if (skb->len < 24) {
-		dev_kfree_skb(skb);
-		return;
-	}
+	if (skb->len < 2)
+		return RX_DROP_UNUSABLE;
 
 	mgmt = (struct ieee80211_mgmt *) skb->data;
 	fc = le16_to_cpu(mgmt->frame_control);
 
+	if ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_CTL)
+		return RX_CONTINUE;
+
+	if (skb->len < 24)
+		return RX_DROP_MONITOR;
+
 	if ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT) {
 		if ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_PROBE_RESP) {
 			ieee80211_rx_mgmt_probe_resp(dev, mgmt,
 						     skb->len, rx_status);
+			dev_kfree_skb(skb);
+			return RX_QUEUED;
 		} else if ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_BEACON) {
 			ieee80211_rx_mgmt_beacon(dev, mgmt, skb->len,
 						 rx_status);
+			dev_kfree_skb(skb);
+			return RX_QUEUED;
 		}
 	}
-
-	dev_kfree_skb(skb);
+	return RX_CONTINUE;
 }
 
 
@@ -1924,13 +2620,14 @@ static void ieee80211_sta_expire(struct net_device *dev)
 	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
 	struct sta_info *sta, *tmp;
 	LIST_HEAD(tmp_list);
+	DECLARE_MAC_BUF(mac);
 
 	write_lock_bh(&local->sta_lock);
 	list_for_each_entry_safe(sta, tmp, &local->sta_list, list)
 		if (time_after(jiffies, sta->last_rx +
 			       IEEE80211_IBSS_INACTIVITY_LIMIT)) {
-			printk(KERN_DEBUG "%s: expiring inactive STA " MAC_FMT
-			       "\n", dev->name, MAC_ARG(sta->addr));
+			printk(KERN_DEBUG "%s: expiring inactive STA %s\n",
+			       dev->name, print_mac(mac, sta->addr));
 			__sta_info_get(sta);
 			sta_info_remove(sta);
 			list_add(&sta->list, &tmp_list);
@@ -1983,13 +2680,13 @@ void ieee80211_sta_work(struct work_struct *work)
 	if (!netif_running(dev))
 		return;
 
-	if (local->sta_scanning)
+	if (local->sta_sw_scanning || local->sta_hw_scanning)
 		return;
 
-	if (sdata->type != IEEE80211_IF_TYPE_STA &&
-	    sdata->type != IEEE80211_IF_TYPE_IBSS) {
+	if (sdata->vif.type != IEEE80211_IF_TYPE_STA &&
+	    sdata->vif.type != IEEE80211_IF_TYPE_IBSS) {
 		printk(KERN_DEBUG "%s: ieee80211_sta_work: non-STA interface "
-		       "(type=%d)\n", dev->name, sdata->type);
+		       "(type=%d)\n", dev->name, sdata->vif.type);
 		return;
 	}
 	ifsta = &sdata->u.sta;
@@ -2000,7 +2697,10 @@ void ieee80211_sta_work(struct work_struct *work)
 	if (ifsta->state != IEEE80211_AUTHENTICATE &&
 	    ifsta->state != IEEE80211_ASSOCIATE &&
 	    test_and_clear_bit(IEEE80211_STA_REQ_SCAN, &ifsta->request)) {
-		ieee80211_sta_start_scan(dev, NULL, 0);
+		if (ifsta->scan_ssid_len)
+			ieee80211_sta_start_scan(dev, ifsta->scan_ssid, ifsta->scan_ssid_len);
+		else
+			ieee80211_sta_start_scan(dev, NULL, 0);
 		return;
 	}
 
@@ -2081,7 +2781,7 @@ void ieee80211_sta_req_auth(struct net_device *dev,
 	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
 	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
 
-	if (sdata->type != IEEE80211_IF_TYPE_STA)
+	if (sdata->vif.type != IEEE80211_IF_TYPE_STA)
 		return;
 
 	if ((ifsta->flags & (IEEE80211_STA_BSSID_SET |
@@ -2098,7 +2798,8 @@ static int ieee80211_sta_match_ssid(struct ieee80211_if_sta *ifsta,
 {
 	int tmp, hidden_ssid;
 
-	if (!memcmp(ifsta->ssid, ssid, ssid_len))
+	if (ssid_len == ifsta->ssid_len &&
+	    !memcmp(ifsta->ssid, ssid, ssid_len))
 		return 1;
 
 	if (ifsta->flags & IEEE80211_STA_AUTO_BSSID_SEL)
@@ -2138,7 +2839,7 @@ static int ieee80211_sta_config_auth(struct net_device *dev,
 	}
 
 	spin_lock_bh(&local->sta_bss_lock);
-	freq = local->oper_channel->freq;
+	freq = local->oper_channel->center_freq;
 	list_for_each_entry(bss, &local->sta_bss_list, list) {
 		if (!(bss->capability & WLAN_CAPABILITY_ESS))
 			continue;
@@ -2169,7 +2870,7 @@ static int ieee80211_sta_config_auth(struct net_device *dev,
 	spin_unlock_bh(&local->sta_bss_lock);
 
 	if (selected) {
-		ieee80211_set_channel(local, -1, selected->freq);
+		ieee80211_set_freq(local, selected->freq);
 		if (!(ifsta->flags & IEEE80211_STA_SSID_SET))
 			ieee80211_sta_set_ssid(dev, selected->ssid,
 					       selected->ssid_len);
@@ -2202,11 +2903,12 @@ static int ieee80211_sta_join_ibss(struct net_device *dev,
 	struct sk_buff *skb;
 	struct ieee80211_mgmt *mgmt;
 	struct ieee80211_tx_control control;
-	struct ieee80211_rate *rate;
-	struct ieee80211_hw_mode *mode;
-	struct rate_control_extra extra;
+	struct rate_selection ratesel;
 	u8 *pos;
 	struct ieee80211_sub_if_data *sdata;
+	struct ieee80211_supported_band *sband;
+
+	sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
 
 	/* Remove possible STA entries from other IBSS networks. */
 	sta_info_flush(local, NULL);
@@ -2226,12 +2928,11 @@ static int ieee80211_sta_join_ibss(struct net_device *dev,
 	sdata->drop_unencrypted = bss->capability &
 		WLAN_CAPABILITY_PRIVACY ? 1 : 0;
 
-	res = ieee80211_set_channel(local, -1, bss->freq);
+	res = ieee80211_set_freq(local, bss->freq);
 
-	if (!(local->oper_channel->flag & IEEE80211_CHAN_W_IBSS)) {
-		printk(KERN_DEBUG "%s: IBSS not allowed on channel %d "
-		       "(%d MHz)\n", dev->name, local->hw.conf.channel,
-		       local->hw.conf.freq);
+	if (local->oper_channel->flags & IEEE80211_CHAN_NO_IBSS) {
+		printk(KERN_DEBUG "%s: IBSS not allowed on frequency "
+		       "%d MHz\n", dev->name, local->oper_channel->center_freq);
 		return -1;
 	}
 
@@ -2268,10 +2969,12 @@ static int ieee80211_sta_join_ibss(struct net_device *dev,
 		*pos++ = rates;
 		memcpy(pos, bss->supp_rates, rates);
 
-		pos = skb_put(skb, 2 + 1);
-		*pos++ = WLAN_EID_DS_PARAMS;
-		*pos++ = 1;
-		*pos++ = bss->channel;
+		if (bss->band == IEEE80211_BAND_2GHZ) {
+			pos = skb_put(skb, 2 + 1);
+			*pos++ = WLAN_EID_DS_PARAMS;
+			*pos++ = 1;
+			*pos++ = ieee80211_frequency_to_channel(bss->freq);
+		}
 
 		pos = skb_put(skb, 2 + 2);
 		*pos++ = WLAN_EID_IBSS_PARAMS;
@@ -2289,20 +2992,18 @@ static int ieee80211_sta_join_ibss(struct net_device *dev,
 		}
 
 		memset(&control, 0, sizeof(control));
-		memset(&extra, 0, sizeof(extra));
-		extra.mode = local->oper_hw_mode;
-		rate = rate_control_get_rate(local, dev, skb, &extra);
-		if (!rate) {
+		rate_control_get_rate(dev, sband, skb, &ratesel);
+		if (!ratesel.rate) {
 			printk(KERN_DEBUG "%s: Failed to determine TX rate "
 			       "for IBSS beacon\n", dev->name);
 			break;
 		}
-		control.tx_rate =
-			((sdata->flags & IEEE80211_SDATA_SHORT_PREAMBLE) &&
-			(rate->flags & IEEE80211_RATE_PREAMBLE2)) ?
-			rate->val2 : rate->val;
+		control.vif = &sdata->vif;
+		control.tx_rate = ratesel.rate;
+		if (sdata->bss_conf.use_short_preamble &&
+		    ratesel.rate->flags & IEEE80211_RATE_SHORT_PREAMBLE)
+			control.flags |= IEEE80211_TXCTL_SHORT_PREAMBLE;
 		control.antenna_sel_tx = local->hw.conf.antenna_sel_tx;
-		control.power_level = local->hw.conf.power_level;
 		control.flags |= IEEE80211_TXCTL_NO_ACK;
 		control.retry_limit = 1;
 
@@ -2327,14 +3028,14 @@ static int ieee80211_sta_join_ibss(struct net_device *dev,
 		}
 
 		rates = 0;
-		mode = local->oper_hw_mode;
+		sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
 		for (i = 0; i < bss->supp_rates_len; i++) {
 			int bitrate = (bss->supp_rates[i] & 0x7f) * 5;
-			for (j = 0; j < mode->num_rates; j++)
-				if (mode->rates[j].rate == bitrate)
+			for (j = 0; j < sband->n_bitrates; j++)
+				if (sband->bitrates[j].bitrate == bitrate)
 					rates |= BIT(j);
 		}
-		ifsta->supp_rates_bits = rates;
+		ifsta->supp_rates_bits[local->hw.conf.channel->band] = rates;
 	} while (0);
 
 	if (skb) {
@@ -2357,10 +3058,11 @@ static int ieee80211_sta_create_ibss(struct net_device *dev,
 {
 	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
 	struct ieee80211_sta_bss *bss;
-	struct ieee80211_sub_if_data *sdata;
-	struct ieee80211_hw_mode *mode;
+	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+	struct ieee80211_supported_band *sband;
 	u8 bssid[ETH_ALEN], *pos;
 	int i;
+	DECLARE_MAC_BUF(mac);
 
 #if 0
 	/* Easier testing, use fixed BSSID. */
@@ -2376,32 +3078,31 @@ static int ieee80211_sta_create_ibss(struct net_device *dev,
 	bssid[0] |= 0x02;
 #endif
 
-	printk(KERN_DEBUG "%s: Creating new IBSS network, BSSID " MAC_FMT "\n",
-	       dev->name, MAC_ARG(bssid));
+	printk(KERN_DEBUG "%s: Creating new IBSS network, BSSID %s\n",
+	       dev->name, print_mac(mac, bssid));
 
-	bss = ieee80211_rx_bss_add(dev, bssid);
+	bss = ieee80211_rx_bss_add(dev, bssid,
+				   local->hw.conf.channel->center_freq,
+				   sdata->u.sta.ssid, sdata->u.sta.ssid_len);
 	if (!bss)
 		return -ENOMEM;
 
-	sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-	mode = local->oper_hw_mode;
+	bss->band = local->hw.conf.channel->band;
+	sband = local->hw.wiphy->bands[bss->band];
 
 	if (local->hw.conf.beacon_int == 0)
 		local->hw.conf.beacon_int = 100;
 	bss->beacon_int = local->hw.conf.beacon_int;
-	bss->hw_mode = local->hw.conf.phymode;
-	bss->channel = local->hw.conf.channel;
-	bss->freq = local->hw.conf.freq;
 	bss->last_update = jiffies;
 	bss->capability = WLAN_CAPABILITY_IBSS;
 	if (sdata->default_key) {
 		bss->capability |= WLAN_CAPABILITY_PRIVACY;
 	} else
 		sdata->drop_unencrypted = 0;
-	bss->supp_rates_len = mode->num_rates;
+	bss->supp_rates_len = sband->n_bitrates;
 	pos = bss->supp_rates;
-	for (i = 0; i < mode->num_rates; i++) {
-		int rate = mode->rates[i].rate;
+	for (i = 0; i < sband->n_bitrates; i++) {
+		int rate = sband->bitrates[i].bitrate;
 		*pos++ = (u8) (rate / 5);
 	}
 
@@ -2417,6 +3118,8 @@ static int ieee80211_sta_find_ibss(struct net_device *dev,
 	int found = 0;
 	u8 bssid[ETH_ALEN];
 	int active_ibss;
+	DECLARE_MAC_BUF(mac);
+	DECLARE_MAC_BUF(mac2);
 
 	if (ifsta->ssid_len == 0)
 		return -EINVAL;
@@ -2433,8 +3136,8 @@ static int ieee80211_sta_find_ibss(struct net_device *dev,
 		    || !(bss->capability & WLAN_CAPABILITY_IBSS))
 			continue;
 #ifdef CONFIG_MAC80211_IBSS_DEBUG
-		printk(KERN_DEBUG "   bssid=" MAC_FMT " found\n",
-		       MAC_ARG(bss->bssid));
+		printk(KERN_DEBUG "   bssid=%s found\n",
+		       print_mac(mac, bss->bssid));
 #endif /* CONFIG_MAC80211_IBSS_DEBUG */
 		memcpy(bssid, bss->bssid, ETH_ALEN);
 		found = 1;
@@ -2444,14 +3147,16 @@ static int ieee80211_sta_find_ibss(struct net_device *dev,
 	spin_unlock_bh(&local->sta_bss_lock);
 
 #ifdef CONFIG_MAC80211_IBSS_DEBUG
-	printk(KERN_DEBUG "   sta_find_ibss: selected " MAC_FMT " current "
-	       MAC_FMT "\n", MAC_ARG(bssid), MAC_ARG(ifsta->bssid));
+	printk(KERN_DEBUG "   sta_find_ibss: selected %s current "
+	       "%s\n", print_mac(mac, bssid), print_mac(mac2, ifsta->bssid));
 #endif /* CONFIG_MAC80211_IBSS_DEBUG */
 	if (found && memcmp(ifsta->bssid, bssid, ETH_ALEN) != 0 &&
-	    (bss = ieee80211_rx_bss_get(dev, bssid))) {
-		printk(KERN_DEBUG "%s: Selected IBSS BSSID " MAC_FMT
+	    (bss = ieee80211_rx_bss_get(dev, bssid,
+					local->hw.conf.channel->center_freq,
+					ifsta->ssid, ifsta->ssid_len))) {
+		printk(KERN_DEBUG "%s: Selected IBSS BSSID %s"
 		       " based on configured SSID\n",
-		       dev->name, MAC_ARG(bssid));
+		       dev->name, print_mac(mac, bssid));
 		return ieee80211_sta_join_ibss(dev, ifsta, bss);
 	}
 #ifdef CONFIG_MAC80211_IBSS_DEBUG
@@ -2475,13 +3180,13 @@ static int ieee80211_sta_find_ibss(struct net_device *dev,
 		if (time_after(jiffies, ifsta->ibss_join_req +
 			       IEEE80211_IBSS_JOIN_TIMEOUT)) {
 			if ((ifsta->flags & IEEE80211_STA_CREATE_IBSS) &&
-			    local->oper_channel->flag & IEEE80211_CHAN_W_IBSS)
+			    (!(local->oper_channel->flags &
+					IEEE80211_CHAN_NO_IBSS)))
 				return ieee80211_sta_create_ibss(dev, ifsta);
 			if (ifsta->flags & IEEE80211_STA_CREATE_IBSS) {
-				printk(KERN_DEBUG "%s: IBSS not allowed on the"
-				       " configured channel %d (%d MHz)\n",
-				       dev->name, local->hw.conf.channel,
-				       local->hw.conf.freq);
+				printk(KERN_DEBUG "%s: IBSS not allowed on"
+				       " %d MHz\n", dev->name,
+				       local->hw.conf.channel->center_freq);
 			}
 
 			/* No IBSS found - decrease scan interval and continue
@@ -2500,7 +3205,7 @@ static int ieee80211_sta_find_ibss(struct net_device *dev,
 
 int ieee80211_sta_set_ssid(struct net_device *dev, char *ssid, size_t len)
 {
-	struct ieee80211_sub_if_data *sdata;
+	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
 	struct ieee80211_if_sta *ifsta;
 	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
 
@@ -2514,18 +3219,23 @@ int ieee80211_sta_set_ssid(struct net_device *dev, char *ssid, size_t len)
 		int i;
 
 		memset(&qparam, 0, sizeof(qparam));
-		/* TODO: are these ok defaults for all hw_modes? */
+
 		qparam.aifs = 2;
-		qparam.cw_min =
-			local->hw.conf.phymode == MODE_IEEE80211B ? 31 : 15;
+
+		if (local->hw.conf.channel->band == IEEE80211_BAND_2GHZ &&
+		    !(sdata->flags & IEEE80211_SDATA_OPERATING_GMODE))
+			qparam.cw_min = 31;
+		else
+			qparam.cw_min = 15;
+
 		qparam.cw_max = 1023;
 		qparam.burst_time = 0;
+
 		for (i = IEEE80211_TX_QUEUE_DATA0; i < NUM_TX_DATA_QUEUES; i++)
-		{
 			local->ops->conf_tx(local_to_hw(local),
 					   i + IEEE80211_TX_QUEUE_DATA0,
 					   &qparam);
-		}
+
 		/* IBSS uses different parameters for Beacon sending */
 		qparam.cw_min++;
 		qparam.cw_min *= 2;
@@ -2534,7 +3244,6 @@ int ieee80211_sta_set_ssid(struct net_device *dev, char *ssid, size_t len)
 				   IEEE80211_TX_QUEUE_BEACON, &qparam);
 	}
 
-	sdata = IEEE80211_DEV_TO_SUB_IF(dev);
 	ifsta = &sdata->u.sta;
 
 	if (ifsta->ssid_len != len || memcmp(ifsta->ssid, ssid, len) != 0)
@@ -2547,7 +3256,7 @@ int ieee80211_sta_set_ssid(struct net_device *dev, char *ssid, size_t len)
 		ifsta->flags |= IEEE80211_STA_SSID_SET;
 	else
 		ifsta->flags &= ~IEEE80211_STA_SSID_SET;
-	if (sdata->type == IEEE80211_IF_TYPE_IBSS &&
+	if (sdata->vif.type == IEEE80211_IF_TYPE_IBSS &&
 	    !(ifsta->flags & IEEE80211_STA_BSSID_SET)) {
 		ifsta->ibss_join_req = jiffies;
 		ifsta->state = IEEE80211_IBSS_SEARCH;
@@ -2634,11 +3343,17 @@ void ieee80211_scan_completed(struct ieee80211_hw *hw)
 	union iwreq_data wrqu;
 
 	local->last_scan_completed = jiffies;
-	wmb();
-	local->sta_scanning = 0;
+	memset(&wrqu, 0, sizeof(wrqu));
+	wireless_send_event(dev, SIOCGIWSCAN, &wrqu, NULL);
 
+	if (local->sta_hw_scanning) {
+		local->sta_hw_scanning = 0;
+		goto done;
+	}
+
+	local->sta_sw_scanning = 0;
 	if (ieee80211_hw_config(local))
-		printk(KERN_DEBUG "%s: failed to restore operational"
+		printk(KERN_DEBUG "%s: failed to restore operational "
 		       "channel after scan\n", dev->name);
 
 
@@ -2652,9 +3367,6 @@ void ieee80211_scan_completed(struct ieee80211_hw *hw)
 
 	netif_tx_unlock_bh(local->mdev);
 
-	memset(&wrqu, 0, sizeof(wrqu));
-	wireless_send_event(dev, SIOCGIWSCAN, &wrqu, NULL);
-
 	rcu_read_lock();
 	list_for_each_entry_rcu(sdata, &local->interfaces, list) {
 
@@ -2662,7 +3374,7 @@ void ieee80211_scan_completed(struct ieee80211_hw *hw)
 		if (sdata->dev == local->mdev)
 			continue;
 
-		if (sdata->type == IEEE80211_IF_TYPE_STA) {
+		if (sdata->vif.type == IEEE80211_IF_TYPE_STA) {
 			if (sdata->u.sta.flags & IEEE80211_STA_ASSOCIATED)
 				ieee80211_send_nullfunc(local, sdata, 0);
 			ieee80211_sta_timer((unsigned long)sdata);
@@ -2672,8 +3384,9 @@ void ieee80211_scan_completed(struct ieee80211_hw *hw)
 	}
 	rcu_read_unlock();
 
+done:
 	sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-	if (sdata->type == IEEE80211_IF_TYPE_IBSS) {
+	if (sdata->vif.type == IEEE80211_IF_TYPE_IBSS) {
 		struct ieee80211_if_sta *ifsta = &sdata->u.sta;
 		if (!(ifsta->flags & IEEE80211_STA_BSSID_SET) ||
 		    (!ifsta->state == IEEE80211_IBSS_JOINED &&
@@ -2689,54 +3402,69 @@ void ieee80211_sta_scan_work(struct work_struct *work)
 		container_of(work, struct ieee80211_local, scan_work.work);
 	struct net_device *dev = local->scan_dev;
 	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-	struct ieee80211_hw_mode *mode;
+	struct ieee80211_supported_band *sband;
 	struct ieee80211_channel *chan;
 	int skip;
 	unsigned long next_delay = 0;
 
-	if (!local->sta_scanning)
+	if (!local->sta_sw_scanning)
 		return;
 
 	switch (local->scan_state) {
 	case SCAN_SET_CHANNEL:
-		mode = local->scan_hw_mode;
-		if (local->scan_hw_mode->list.next == &local->modes_list &&
-		    local->scan_channel_idx >= mode->num_channels) {
+		/*
+		 * Get current scan band. scan_band may be IEEE80211_NUM_BANDS
+		 * after we successfully scanned the last channel of the last
+		 * band (and the last band is supported by the hw)
+		 */
+		if (local->scan_band < IEEE80211_NUM_BANDS)
+			sband = local->hw.wiphy->bands[local->scan_band];
+		else
+			sband = NULL;
+
+		/*
+		 * If we are at an unsupported band and have more bands
+		 * left to scan, advance to the next supported one.
+		 */
+		while (!sband && local->scan_band < IEEE80211_NUM_BANDS - 1) {
+			local->scan_band++;
+			sband = local->hw.wiphy->bands[local->scan_band];
+			local->scan_channel_idx = 0;
+		}
+
+		/* if no more bands/channels left, complete scan */
+		if (!sband || local->scan_channel_idx >= sband->n_channels) {
 			ieee80211_scan_completed(local_to_hw(local));
 			return;
 		}
-		skip = !(local->enabled_modes & (1 << mode->mode));
-		chan = &mode->channels[local->scan_channel_idx];
-		if (!(chan->flag & IEEE80211_CHAN_W_SCAN) ||
-		    (sdata->type == IEEE80211_IF_TYPE_IBSS &&
-		     !(chan->flag & IEEE80211_CHAN_W_IBSS)) ||
-		    (local->hw_modes & local->enabled_modes &
-		     (1 << MODE_IEEE80211G) && mode->mode == MODE_IEEE80211B))
+		skip = 0;
+		chan = &sband->channels[local->scan_channel_idx];
+
+		if (chan->flags & IEEE80211_CHAN_DISABLED ||
+		    (sdata->vif.type == IEEE80211_IF_TYPE_IBSS &&
+		     chan->flags & IEEE80211_CHAN_NO_IBSS))
 			skip = 1;
 
 		if (!skip) {
-#if 0
-			printk(KERN_DEBUG "%s: scan channel %d (%d MHz)\n",
-			       dev->name, chan->chan, chan->freq);
-#endif
-
 			local->scan_channel = chan;
 			if (ieee80211_hw_config(local)) {
-				printk(KERN_DEBUG "%s: failed to set channel "
-				       "%d (%d MHz) for scan\n", dev->name,
-				       chan->chan, chan->freq);
+				printk(KERN_DEBUG "%s: failed to set freq to "
+				       "%d MHz for scan\n", dev->name,
+				       chan->center_freq);
 				skip = 1;
 			}
 		}
 
+		/* advance state machine to next channel/band */
 		local->scan_channel_idx++;
-		if (local->scan_channel_idx >= local->scan_hw_mode->num_channels) {
-			if (local->scan_hw_mode->list.next != &local->modes_list) {
-				local->scan_hw_mode = list_entry(local->scan_hw_mode->list.next,
-								 struct ieee80211_hw_mode,
-								 list);
-				local->scan_channel_idx = 0;
-			}
+		if (local->scan_channel_idx >= sband->n_channels) {
+			/*
+			 * scan_band may end up == IEEE80211_NUM_BANDS, but
+			 * we'll catch that case above and complete the scan
+			 * if that is the case.
+			 */
+			local->scan_band++;
+			local->scan_channel_idx = 0;
 		}
 
 		if (skip)
@@ -2747,17 +3475,18 @@ void ieee80211_sta_scan_work(struct work_struct *work)
 		local->scan_state = SCAN_SEND_PROBE;
 		break;
 	case SCAN_SEND_PROBE:
-		if (local->scan_channel->flag & IEEE80211_CHAN_W_ACTIVE_SCAN) {
-			ieee80211_send_probe_req(dev, NULL, local->scan_ssid,
-						 local->scan_ssid_len);
-			next_delay = IEEE80211_CHANNEL_TIME;
-		} else
-			next_delay = IEEE80211_PASSIVE_CHANNEL_TIME;
+		next_delay = IEEE80211_PASSIVE_CHANNEL_TIME;
 		local->scan_state = SCAN_SET_CHANNEL;
+
+		if (local->scan_channel->flags & IEEE80211_CHAN_PASSIVE_SCAN)
+			break;
+		ieee80211_send_probe_req(dev, NULL, local->scan_ssid,
+					 local->scan_ssid_len);
+		next_delay = IEEE80211_CHANNEL_TIME;
 		break;
 	}
 
-	if (local->sta_scanning)
+	if (local->sta_sw_scanning)
 		queue_delayed_work(local->hw.workqueue, &local->scan_work,
 				   next_delay);
 }
@@ -2789,7 +3518,7 @@ static int ieee80211_sta_start_scan(struct net_device *dev,
 	  * ResultCode: SUCCESS, INVALID_PARAMETERS
 	 */
 
-	if (local->sta_scanning) {
+	if (local->sta_sw_scanning || local->sta_hw_scanning) {
 		if (local->scan_dev == dev)
 			return 0;
 		return -EBUSY;
@@ -2797,15 +3526,15 @@ static int ieee80211_sta_start_scan(struct net_device *dev,
 
 	if (local->ops->hw_scan) {
 		int rc = local->ops->hw_scan(local_to_hw(local),
-					    ssid, ssid_len);
+					     ssid, ssid_len);
 		if (!rc) {
-			local->sta_scanning = 1;
+			local->sta_hw_scanning = 1;
 			local->scan_dev = dev;
 		}
 		return rc;
 	}
 
-	local->sta_scanning = 1;
+	local->sta_sw_scanning = 1;
 
 	rcu_read_lock();
 	list_for_each_entry_rcu(sdata, &local->interfaces, list) {
@@ -2816,7 +3545,7 @@ static int ieee80211_sta_start_scan(struct net_device *dev,
 			continue;
 
 		netif_stop_queue(sdata->dev);
-		if (sdata->type == IEEE80211_IF_TYPE_STA &&
+		if (sdata->vif.type == IEEE80211_IF_TYPE_STA &&
 		    (sdata->u.sta.flags & IEEE80211_STA_ASSOCIATED))
 			ieee80211_send_nullfunc(local, sdata, 1);
 	}
@@ -2828,10 +3557,8 @@ static int ieee80211_sta_start_scan(struct net_device *dev,
 	} else
 		local->scan_ssid_len = 0;
 	local->scan_state = SCAN_SET_CHANNEL;
-	local->scan_hw_mode = list_entry(local->modes_list.next,
-					 struct ieee80211_hw_mode,
-					 list);
 	local->scan_channel_idx = 0;
+	local->scan_band = IEEE80211_BAND_2GHZ;
 	local->scan_dev = dev;
 
 	netif_tx_lock_bh(local->mdev);
@@ -2857,15 +3584,18 @@ int ieee80211_sta_req_scan(struct net_device *dev, u8 *ssid, size_t ssid_len)
 	struct ieee80211_if_sta *ifsta = &sdata->u.sta;
 	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
 
-	if (sdata->type != IEEE80211_IF_TYPE_STA)
+	if (sdata->vif.type != IEEE80211_IF_TYPE_STA)
 		return ieee80211_sta_start_scan(dev, ssid, ssid_len);
 
-	if (local->sta_scanning) {
+	if (local->sta_sw_scanning || local->sta_hw_scanning) {
 		if (local->scan_dev == dev)
 			return 0;
 		return -EBUSY;
 	}
 
+	ifsta->scan_ssid_len = ssid_len;
+	if (ssid_len)
+		memcpy(ifsta->scan_ssid, ssid, ssid_len);
 	set_bit(IEEE80211_STA_REQ_SCAN, &ifsta->request);
 	queue_work(local->hw.workqueue, &ifsta->work);
 	return 0;
@@ -2883,18 +3613,6 @@ ieee80211_sta_scan_result(struct net_device *dev,
 		       bss->last_update + IEEE80211_SCAN_RESULT_EXPIRE))
 		return current_ev;
 
-	if (!(local->enabled_modes & (1 << bss->hw_mode)))
-		return current_ev;
-
-	if (local->scan_flags & IEEE80211_SCAN_WPA_ONLY &&
-	    !bss->wpa_ie && !bss->rsn_ie)
-		return current_ev;
-
-	if (local->scan_flags & IEEE80211_SCAN_MATCH_SSID &&
-	    (local->scan_ssid_len != bss->ssid_len ||
-	     memcmp(local->scan_ssid, bss->ssid, bss->ssid_len) != 0))
-		return current_ev;
-
 	memset(&iwe, 0, sizeof(iwe));
 	iwe.cmd = SIOCGIWAP;
 	iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
@@ -2922,12 +3640,15 @@ ieee80211_sta_scan_result(struct net_device *dev,
 
 	memset(&iwe, 0, sizeof(iwe));
 	iwe.cmd = SIOCGIWFREQ;
-	iwe.u.freq.m = bss->channel;
-	iwe.u.freq.e = 0;
+	iwe.u.freq.m = bss->freq;
+	iwe.u.freq.e = 6;
 	current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe,
 					  IW_EV_FREQ_LEN);
-	iwe.u.freq.m = bss->freq * 100000;
-	iwe.u.freq.e = 1;
+
+	memset(&iwe, 0, sizeof(iwe));
+	iwe.cmd = SIOCGIWFREQ;
+	iwe.u.freq.m = ieee80211_frequency_to_channel(bss->freq);
+	iwe.u.freq.e = 0;
 	current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe,
 					  IW_EV_FREQ_LEN);
 
@@ -2998,34 +3719,6 @@ ieee80211_sta_scan_result(struct net_device *dev,
 		}
 	}
 
-	do {
-		char *buf;
-
-		if (!(local->scan_flags & IEEE80211_SCAN_EXTRA_INFO))
-			break;
-
-		buf = kmalloc(100, GFP_ATOMIC);
-		if (!buf)
-			break;
-
-		memset(&iwe, 0, sizeof(iwe));
-		iwe.cmd = IWEVCUSTOM;
-		sprintf(buf, "bcn_int=%d", bss->beacon_int);
-		iwe.u.data.length = strlen(buf);
-		current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe,
-						  buf);
-
-		memset(&iwe, 0, sizeof(iwe));
-		iwe.cmd = IWEVCUSTOM;
-		sprintf(buf, "capab=0x%04x", bss->capability);
-		iwe.u.data.length = strlen(buf);
-		current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe,
-						  buf);
-
-		kfree(buf);
-		break;
-	} while (0);
-
 	return current_ev;
 }
 
@@ -3079,25 +3772,29 @@ struct sta_info * ieee80211_ibss_add_sta(struct net_device *dev,
 	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
 	struct sta_info *sta;
 	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+	DECLARE_MAC_BUF(mac);
 
 	/* TODO: Could consider removing the least recently used entry and
 	 * allow new one to be added. */
 	if (local->num_sta >= IEEE80211_IBSS_MAX_STA_ENTRIES) {
 		if (net_ratelimit()) {
 			printk(KERN_DEBUG "%s: No room for a new IBSS STA "
-			       "entry " MAC_FMT "\n", dev->name, MAC_ARG(addr));
+			       "entry %s\n", dev->name, print_mac(mac, addr));
 		}
 		return NULL;
 	}
 
-	printk(KERN_DEBUG "%s: Adding new IBSS station " MAC_FMT " (dev=%s)\n",
-	       wiphy_name(local->hw.wiphy), MAC_ARG(addr), dev->name);
+	printk(KERN_DEBUG "%s: Adding new IBSS station %s (dev=%s)\n",
+	       wiphy_name(local->hw.wiphy), print_mac(mac, addr), dev->name);
 
 	sta = sta_info_add(local, dev, addr, GFP_ATOMIC);
 	if (!sta)
 		return NULL;
 
-	sta->supp_rates = sdata->u.sta.supp_rates_bits;
+	sta->flags |= WLAN_STA_AUTHORIZED;
+
+	sta->supp_rates[local->hw.conf.channel->band] =
+		sdata->u.sta.supp_rates_bits[local->hw.conf.channel->band];
 
 	rate_control_rate_init(sta, local);
 
@@ -3113,8 +3810,8 @@ int ieee80211_sta_deauthenticate(struct net_device *dev, u16 reason)
 	printk(KERN_DEBUG "%s: deauthenticate(reason=%d)\n",
 	       dev->name, reason);
 
-	if (sdata->type != IEEE80211_IF_TYPE_STA &&
-	    sdata->type != IEEE80211_IF_TYPE_IBSS)
+	if (sdata->vif.type != IEEE80211_IF_TYPE_STA &&
+	    sdata->vif.type != IEEE80211_IF_TYPE_IBSS)
 		return -EINVAL;
 
 	ieee80211_send_deauth(dev, ifsta, reason);
@@ -3131,7 +3828,7 @@ int ieee80211_sta_disassociate(struct net_device *dev, u16 reason)
 	printk(KERN_DEBUG "%s: disassociate(reason=%d)\n",
 	       dev->name, reason);
 
-	if (sdata->type != IEEE80211_IF_TYPE_STA)
+	if (sdata->vif.type != IEEE80211_IF_TYPE_STA)
 		return -EINVAL;
 
 	if (!(ifsta->flags & IEEE80211_STA_ASSOCIATED))
diff --git a/package/mac80211/src/net/mac80211/key.c b/package/mac80211/src/net/mac80211/key.c
index d9ab0871fe..ed57fb8e82 100644
--- a/package/mac80211/src/net/mac80211/key.c
+++ b/package/mac80211/src/net/mac80211/key.c
@@ -49,8 +49,8 @@ static const u8 *get_mac_for_key(struct ieee80211_key *key)
 	 * address to indicate a transmit-only key.
 	 */
 	if (key->conf.alg != ALG_WEP &&
-	    (key->sdata->type == IEEE80211_IF_TYPE_AP ||
-	     key->sdata->type == IEEE80211_IF_TYPE_VLAN))
+	    (key->sdata->vif.type == IEEE80211_IF_TYPE_AP ||
+	     key->sdata->vif.type == IEEE80211_IF_TYPE_VLAN))
 		addr = zero_addr;
 
 	if (key->sta)
@@ -63,6 +63,7 @@ static void ieee80211_key_enable_hw_accel(struct ieee80211_key *key)
 {
 	const u8 *addr;
 	int ret;
+	DECLARE_MAC_BUF(mac);
 
 	if (!key->local->ops->set_key)
 		return;
@@ -78,15 +79,16 @@ static void ieee80211_key_enable_hw_accel(struct ieee80211_key *key)
 
 	if (ret && ret != -ENOSPC && ret != -EOPNOTSUPP)
 		printk(KERN_ERR "mac80211-%s: failed to set key "
-		       "(%d, " MAC_FMT ") to hardware (%d)\n",
+		       "(%d, %s) to hardware (%d)\n",
 		       wiphy_name(key->local->hw.wiphy),
-		       key->conf.keyidx, MAC_ARG(addr), ret);
+		       key->conf.keyidx, print_mac(mac, addr), ret);
 }
 
 static void ieee80211_key_disable_hw_accel(struct ieee80211_key *key)
 {
 	const u8 *addr;
 	int ret;
+	DECLARE_MAC_BUF(mac);
 
 	if (!key->local->ops->set_key)
 		return;
@@ -102,9 +104,9 @@ static void ieee80211_key_disable_hw_accel(struct ieee80211_key *key)
 
 	if (ret)
 		printk(KERN_ERR "mac80211-%s: failed to remove key "
-		       "(%d, " MAC_FMT ") from hardware (%d)\n",
+		       "(%d, %s) from hardware (%d)\n",
 		       wiphy_name(key->local->hw.wiphy),
-		       key->conf.keyidx, MAC_ARG(addr), ret);
+		       key->conf.keyidx, print_mac(mac, addr), ret);
 
 	key->flags &= ~KEY_FLAG_UPLOADED_TO_HARDWARE;
 }
@@ -170,7 +172,7 @@ struct ieee80211_key *ieee80211_key_alloc(struct ieee80211_sub_if_data *sdata,
 		if (sta->flags & WLAN_STA_WME)
 			key->conf.flags |= IEEE80211_KEY_FLAG_WMM_STA;
 	} else {
-		if (sdata->type == IEEE80211_IF_TYPE_STA) {
+		if (sdata->vif.type == IEEE80211_IF_TYPE_STA) {
 			struct sta_info *ap;
 
 			/* same here, the AP could be using QoS */
diff --git a/package/mac80211/src/net/mac80211/rc80211_pid.h b/package/mac80211/src/net/mac80211/rc80211_pid.h
new file mode 100644
index 0000000000..04afc13ed8
--- /dev/null
+++ b/package/mac80211/src/net/mac80211/rc80211_pid.h
@@ -0,0 +1,285 @@
+/*
+ * Copyright 2007, Mattias Nissler <mattias.nissler@gmx.de>
+ * Copyright 2007, Stefano Brivio <stefano.brivio@polimi.it>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef RC80211_PID_H
+#define RC80211_PID_H
+
+/* Sampling period for measuring percentage of failed frames in ms. */
+#define RC_PID_INTERVAL			125
+
+/* Exponential averaging smoothness (used for I part of PID controller) */
+#define RC_PID_SMOOTHING_SHIFT		3
+#define RC_PID_SMOOTHING		(1 << RC_PID_SMOOTHING_SHIFT)
+
+/* Sharpening factor (used for D part of PID controller) */
+#define RC_PID_SHARPENING_FACTOR	0
+#define RC_PID_SHARPENING_DURATION	0
+
+/* Fixed point arithmetic shifting amount. */
+#define RC_PID_ARITH_SHIFT		8
+
+/* Fixed point arithmetic factor. */
+#define RC_PID_ARITH_FACTOR		(1 << RC_PID_ARITH_SHIFT)
+
+/* Proportional PID component coefficient. */
+#define RC_PID_COEFF_P			15
+/* Integral PID component coefficient. */
+#define RC_PID_COEFF_I			9
+/* Derivative PID component coefficient. */
+#define RC_PID_COEFF_D			15
+
+/* Target failed frames rate for the PID controller. NB: This effectively gives
+ * maximum failed frames percentage we're willing to accept. If the wireless
+ * link quality is good, the controller will fail to adjust failed frames
+ * percentage to the target. This is intentional.
+ */
+#define RC_PID_TARGET_PF		14
+
+/* Rate behaviour normalization quantity over time. */
+#define RC_PID_NORM_OFFSET		3
+
+/* Push high rates right after loading. */
+#define RC_PID_FAST_START		0
+
+/* Arithmetic right shift for positive and negative values for ISO C. */
+#define RC_PID_DO_ARITH_RIGHT_SHIFT(x, y) \
+	(x) < 0 ? -((-(x)) >> (y)) : (x) >> (y)
+
+enum rc_pid_event_type {
+	RC_PID_EVENT_TYPE_TX_STATUS,
+	RC_PID_EVENT_TYPE_RATE_CHANGE,
+	RC_PID_EVENT_TYPE_TX_RATE,
+	RC_PID_EVENT_TYPE_PF_SAMPLE,
+};
+
+union rc_pid_event_data {
+	/* RC_PID_EVENT_TX_STATUS */
+	struct {
+		struct ieee80211_tx_status tx_status;
+	};
+	/* RC_PID_EVENT_TYPE_RATE_CHANGE */
+	/* RC_PID_EVENT_TYPE_TX_RATE */
+	struct {
+		int index;
+		int rate;
+	};
+	/* RC_PID_EVENT_TYPE_PF_SAMPLE */
+	struct {
+		s32 pf_sample;
+		s32 prop_err;
+		s32 int_err;
+		s32 der_err;
+	};
+};
+
+struct rc_pid_event {
+	/* The time when the event occured */
+	unsigned long timestamp;
+
+	/* Event ID number */
+	unsigned int id;
+
+	/* Type of event */
+	enum rc_pid_event_type type;
+
+	/* type specific data */
+	union rc_pid_event_data data;
+};
+
+/* Size of the event ring buffer. */
+#define RC_PID_EVENT_RING_SIZE 32
+
+struct rc_pid_event_buffer {
+	/* Counter that generates event IDs */
+	unsigned int ev_count;
+
+	/* Ring buffer of events */
+	struct rc_pid_event ring[RC_PID_EVENT_RING_SIZE];
+
+	/* Index to the entry in events_buf to be reused */
+	unsigned int next_entry;
+
+	/* Lock that guards against concurrent access to this buffer struct */
+	spinlock_t lock;
+
+	/* Wait queue for poll/select and blocking I/O */
+	wait_queue_head_t waitqueue;
+};
+
+struct rc_pid_events_file_info {
+	/* The event buffer we read */
+	struct rc_pid_event_buffer *events;
+
+	/* The entry we have should read next */
+	unsigned int next_entry;
+};
+
+/**
+ * struct rc_pid_debugfs_entries - tunable parameters
+ *
+ * Algorithm parameters, tunable via debugfs.
+ * @dir: the debugfs directory for a specific phy
+ * @target: target percentage for failed frames
+ * @sampling_period: error sampling interval in milliseconds
+ * @coeff_p: absolute value of the proportional coefficient
+ * @coeff_i: absolute value of the integral coefficient
+ * @coeff_d: absolute value of the derivative coefficient
+ * @smoothing_shift: absolute value of the integral smoothing factor (i.e.
+ *	amount of smoothing introduced by the exponential moving average)
+ * @sharpen_factor: absolute value of the derivative sharpening factor (i.e.
+ *	amount of emphasis given to the derivative term after low activity
+ *	events)
+ * @sharpen_duration: duration of the sharpening effect after the detected low
+ *	activity event, relative to sampling_period
+ * @norm_offset: amount of normalization periodically performed on the learnt
+ *	rate behaviour values (lower means we should trust more what we learnt
+ *	about behaviour of rates, higher means we should trust more the natural
+ *	ordering of rates)
+ * @fast_start: if Y, push high rates right after initialization
+ */
+struct rc_pid_debugfs_entries {
+	struct dentry *dir;
+	struct dentry *target;
+	struct dentry *sampling_period;
+	struct dentry *coeff_p;
+	struct dentry *coeff_i;
+	struct dentry *coeff_d;
+	struct dentry *smoothing_shift;
+	struct dentry *sharpen_factor;
+	struct dentry *sharpen_duration;
+	struct dentry *norm_offset;
+	struct dentry *fast_start;
+};
+
+void rate_control_pid_event_tx_status(struct rc_pid_event_buffer *buf,
+					     struct ieee80211_tx_status *stat);
+
+void rate_control_pid_event_rate_change(struct rc_pid_event_buffer *buf,
+					       int index, int rate);
+
+void rate_control_pid_event_tx_rate(struct rc_pid_event_buffer *buf,
+					   int index, int rate);
+
+void rate_control_pid_event_pf_sample(struct rc_pid_event_buffer *buf,
+					     s32 pf_sample, s32 prop_err,
+					     s32 int_err, s32 der_err);
+
+void rate_control_pid_add_sta_debugfs(void *priv, void *priv_sta,
+					     struct dentry *dir);
+
+void rate_control_pid_remove_sta_debugfs(void *priv, void *priv_sta);
+
+struct rc_pid_sta_info {
+	unsigned long last_change;
+	unsigned long last_sample;
+
+	u32 tx_num_failed;
+	u32 tx_num_xmit;
+
+	/* Average failed frames percentage error (i.e. actual vs. target
+	 * percentage), scaled by RC_PID_SMOOTHING. This value is computed
+	 * using using an exponential weighted average technique:
+	 *
+	 *           (RC_PID_SMOOTHING - 1) * err_avg_old + err
+	 * err_avg = ------------------------------------------
+	 *                       RC_PID_SMOOTHING
+	 *
+	 * where err_avg is the new approximation, err_avg_old the previous one
+	 * and err is the error w.r.t. to the current failed frames percentage
+	 * sample. Note that the bigger RC_PID_SMOOTHING the more weight is
+	 * given to the previous estimate, resulting in smoother behavior (i.e.
+	 * corresponding to a longer integration window).
+	 *
+	 * For computation, we actually don't use the above formula, but this
+	 * one:
+	 *
+	 * err_avg_scaled = err_avg_old_scaled - err_avg_old + err
+	 *
+	 * where:
+	 * 	err_avg_scaled = err * RC_PID_SMOOTHING
+	 * 	err_avg_old_scaled = err_avg_old * RC_PID_SMOOTHING
+	 *
+	 * This avoids floating point numbers and the per_failed_old value can
+	 * easily be obtained by shifting per_failed_old_scaled right by
+	 * RC_PID_SMOOTHING_SHIFT.
+	 */
+	s32 err_avg_sc;
+
+	/* Last framed failes percentage sample. */
+	u32 last_pf;
+
+	/* Sharpening needed. */
+	u8 sharp_cnt;
+
+#ifdef CONFIG_MAC80211_DEBUGFS
+	/* Event buffer */
+	struct rc_pid_event_buffer events;
+
+	/* Events debugfs file entry */
+	struct dentry *events_entry;
+#endif
+};
+
+/* Algorithm parameters. We keep them on a per-algorithm approach, so they can
+ * be tuned individually for each interface.
+ */
+struct rc_pid_rateinfo {
+
+	/* Map sorted rates to rates in ieee80211_hw_mode. */
+	int index;
+
+	/* Map rates in ieee80211_hw_mode to sorted rates. */
+	int rev_index;
+
+	/* Did we do any measurement on this rate? */
+	bool valid;
+
+	/* Comparison with the lowest rate. */
+	int diff;
+};
+
+struct rc_pid_info {
+
+	/* The failed frames percentage target. */
+	unsigned int target;
+
+	/* Rate at which failed frames percentage is sampled in 0.001s. */
+	unsigned int sampling_period;
+
+	/* P, I and D coefficients. */
+	int coeff_p;
+	int coeff_i;
+	int coeff_d;
+
+	/* Exponential averaging shift. */
+	unsigned int smoothing_shift;
+
+	/* Sharpening factor and duration. */
+	unsigned int sharpen_factor;
+	unsigned int sharpen_duration;
+
+	/* Normalization offset. */
+	unsigned int norm_offset;
+
+	/* Fast starst parameter. */
+	unsigned int fast_start;
+
+	/* Rates information. */
+	struct rc_pid_rateinfo *rinfo;
+
+	/* Index of the last used rate. */
+	int oldrate;
+
+#ifdef CONFIG_MAC80211_DEBUGFS
+	/* Debugfs entries created for the parameters above. */
+	struct rc_pid_debugfs_entries dentries;
+#endif
+};
+
+#endif /* RC80211_PID_H */
diff --git a/package/mac80211/src/net/mac80211/rc80211_pid_algo.c b/package/mac80211/src/net/mac80211/rc80211_pid_algo.c
new file mode 100644
index 0000000000..da8462bbd5
--- /dev/null
+++ b/package/mac80211/src/net/mac80211/rc80211_pid_algo.c
@@ -0,0 +1,550 @@
+/*
+ * Copyright 2002-2005, Instant802 Networks, Inc.
+ * Copyright 2005, Devicescape Software, Inc.
+ * Copyright 2007, Mattias Nissler <mattias.nissler@gmx.de>
+ * Copyright 2007-2008, Stefano Brivio <stefano.brivio@polimi.it>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/netdevice.h>
+#include <linux/types.h>
+#include <linux/skbuff.h>
+#include <linux/debugfs.h>
+#include <net/mac80211.h>
+#include "ieee80211_rate.h"
+
+#include "rc80211_pid.h"
+
+
+/* This is an implementation of a TX rate control algorithm that uses a PID
+ * controller. Given a target failed frames rate, the controller decides about
+ * TX rate changes to meet the target failed frames rate.
+ *
+ * The controller basically computes the following:
+ *
+ * adj = CP * err + CI * err_avg + CD * (err - last_err) * (1 + sharpening)
+ *
+ * where
+ * 	adj	adjustment value that is used to switch TX rate (see below)
+ * 	err	current error: target vs. current failed frames percentage
+ * 	last_err	last error
+ * 	err_avg	average (i.e. poor man's integral) of recent errors
+ *	sharpening	non-zero when fast response is needed (i.e. right after
+ *			association or no frames sent for a long time), heading
+ * 			to zero over time
+ * 	CP	Proportional coefficient
+ * 	CI	Integral coefficient
+ * 	CD	Derivative coefficient
+ *
+ * CP, CI, CD are subject to careful tuning.
+ *
+ * The integral component uses a exponential moving average approach instead of
+ * an actual sliding window. The advantage is that we don't need to keep an
+ * array of the last N error values and computation is easier.
+ *
+ * Once we have the adj value, we map it to a rate by means of a learning
+ * algorithm. This algorithm keeps the state of the percentual failed frames
+ * difference between rates. The behaviour of the lowest available rate is kept
+ * as a reference value, and every time we switch between two rates, we compute
+ * the difference between the failed frames each rate exhibited. By doing so,
+ * we compare behaviours which different rates exhibited in adjacent timeslices,
+ * thus the comparison is minimally affected by external conditions. This
+ * difference gets propagated to the whole set of measurements, so that the
+ * reference is always the same. Periodically, we normalize this set so that
+ * recent events weigh the most. By comparing the adj value with this set, we
+ * avoid pejorative switches to lower rates and allow for switches to higher
+ * rates if they behaved well.
+ *
+ * Note that for the computations we use a fixed-point representation to avoid
+ * floating point arithmetic. Hence, all values are shifted left by
+ * RC_PID_ARITH_SHIFT.
+ */
+
+
+/* Adjust the rate while ensuring that we won't switch to a lower rate if it
+ * exhibited a worse failed frames behaviour and we'll choose the highest rate
+ * whose failed frames behaviour is not worse than the one of the original rate
+ * target. While at it, check that the new rate is valid. */
+static void rate_control_pid_adjust_rate(struct ieee80211_local *local,
+					 struct sta_info *sta, int adj,
+					 struct rc_pid_rateinfo *rinfo)
+{
+	struct ieee80211_sub_if_data *sdata;
+	struct ieee80211_supported_band *sband;
+	int cur_sorted, new_sorted, probe, tmp, n_bitrates, band;
+	int cur = sta->txrate_idx;
+
+	sdata = IEEE80211_DEV_TO_SUB_IF(sta->dev);
+	sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
+	band = sband->band;
+	n_bitrates = sband->n_bitrates;
+
+	/* Map passed arguments to sorted values. */
+	cur_sorted = rinfo[cur].rev_index;
+	new_sorted = cur_sorted + adj;
+
+	/* Check limits. */
+	if (new_sorted < 0)
+		new_sorted = rinfo[0].rev_index;
+	else if (new_sorted >= n_bitrates)
+		new_sorted = rinfo[n_bitrates - 1].rev_index;
+
+	tmp = new_sorted;
+
+	if (adj < 0) {
+		/* Ensure that the rate decrease isn't disadvantageous. */
+		for (probe = cur_sorted; probe >= new_sorted; probe--)
+			if (rinfo[probe].diff <= rinfo[cur_sorted].diff &&
+			    rate_supported(sta, band, rinfo[probe].index))
+				tmp = probe;
+	} else {
+		/* Look for rate increase with zero (or below) cost. */
+		for (probe = new_sorted + 1; probe < n_bitrates; probe++)
+			if (rinfo[probe].diff <= rinfo[new_sorted].diff &&
+			    rate_supported(sta, band, rinfo[probe].index))
+				tmp = probe;
+	}
+
+	/* Fit the rate found to the nearest supported rate. */
+	do {
+		if (rate_supported(sta, band, rinfo[tmp].index)) {
+			sta->txrate_idx = rinfo[tmp].index;
+			break;
+		}
+		if (adj < 0)
+			tmp--;
+		else
+			tmp++;
+	} while (tmp < n_bitrates && tmp >= 0);
+
+#ifdef CONFIG_MAC80211_DEBUGFS
+	rate_control_pid_event_rate_change(
+		&((struct rc_pid_sta_info *)sta->rate_ctrl_priv)->events,
+		sta->txrate_idx, sband->bitrates[sta->txrate_idx].bitrate);
+#endif
+}
+
+/* Normalize the failed frames per-rate differences. */
+static void rate_control_pid_normalize(struct rc_pid_info *pinfo, int l)
+{
+	int i, norm_offset = pinfo->norm_offset;
+	struct rc_pid_rateinfo *r = pinfo->rinfo;
+
+	if (r[0].diff > norm_offset)
+		r[0].diff -= norm_offset;
+	else if (r[0].diff < -norm_offset)
+		r[0].diff += norm_offset;
+	for (i = 0; i < l - 1; i++)
+		if (r[i + 1].diff > r[i].diff + norm_offset)
+			r[i + 1].diff -= norm_offset;
+		else if (r[i + 1].diff <= r[i].diff)
+			r[i + 1].diff += norm_offset;
+}
+
+static void rate_control_pid_sample(struct rc_pid_info *pinfo,
+				    struct ieee80211_local *local,
+				    struct sta_info *sta)
+{
+	struct rc_pid_sta_info *spinfo = sta->rate_ctrl_priv;
+	struct rc_pid_rateinfo *rinfo = pinfo->rinfo;
+	struct ieee80211_supported_band *sband;
+	u32 pf;
+	s32 err_avg;
+	u32 err_prop;
+	u32 err_int;
+	u32 err_der;
+	int adj, i, j, tmp;
+	unsigned long period;
+
+	sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
+	spinfo = sta->rate_ctrl_priv;
+
+	/* In case nothing happened during the previous control interval, turn
+	 * the sharpening factor on. */
+	period = (HZ * pinfo->sampling_period + 500) / 1000;
+	if (!period)
+		period = 1;
+	if (jiffies - spinfo->last_sample > 2 * period)
+		spinfo->sharp_cnt = pinfo->sharpen_duration;
+
+	spinfo->last_sample = jiffies;
+
+	/* This should never happen, but in case, we assume the old sample is
+	 * still a good measurement and copy it. */
+	if (unlikely(spinfo->tx_num_xmit == 0))
+		pf = spinfo->last_pf;
+	else {
+		pf = spinfo->tx_num_failed * 100 / spinfo->tx_num_xmit;
+		pf <<= RC_PID_ARITH_SHIFT;
+	}
+
+	spinfo->tx_num_xmit = 0;
+	spinfo->tx_num_failed = 0;
+
+	/* If we just switched rate, update the rate behaviour info. */
+	if (pinfo->oldrate != sta->txrate_idx) {
+
+		i = rinfo[pinfo->oldrate].rev_index;
+		j = rinfo[sta->txrate_idx].rev_index;
+
+		tmp = (pf - spinfo->last_pf);
+		tmp = RC_PID_DO_ARITH_RIGHT_SHIFT(tmp, RC_PID_ARITH_SHIFT);
+
+		rinfo[j].diff = rinfo[i].diff + tmp;
+		pinfo->oldrate = sta->txrate_idx;
+	}
+	rate_control_pid_normalize(pinfo, sband->n_bitrates);
+
+	/* Compute the proportional, integral and derivative errors. */
+	err_prop = (pinfo->target << RC_PID_ARITH_SHIFT) - pf;
+
+	err_avg = spinfo->err_avg_sc >> pinfo->smoothing_shift;
+	spinfo->err_avg_sc = spinfo->err_avg_sc - err_avg + err_prop;
+	err_int = spinfo->err_avg_sc >> pinfo->smoothing_shift;
+
+	err_der = (pf - spinfo->last_pf) *
+		  (1 + pinfo->sharpen_factor * spinfo->sharp_cnt);
+	spinfo->last_pf = pf;
+	if (spinfo->sharp_cnt)
+			spinfo->sharp_cnt--;
+
+#ifdef CONFIG_MAC80211_DEBUGFS
+	rate_control_pid_event_pf_sample(&spinfo->events, pf, err_prop, err_int,
+					 err_der);
+#endif
+
+	/* Compute the controller output. */
+	adj = (err_prop * pinfo->coeff_p + err_int * pinfo->coeff_i
+	      + err_der * pinfo->coeff_d);
+	adj = RC_PID_DO_ARITH_RIGHT_SHIFT(adj, 2 * RC_PID_ARITH_SHIFT);
+
+	/* Change rate. */
+	if (adj)
+		rate_control_pid_adjust_rate(local, sta, adj, rinfo);
+}
+
+static void rate_control_pid_tx_status(void *priv, struct net_device *dev,
+				       struct sk_buff *skb,
+				       struct ieee80211_tx_status *status)
+{
+	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
+	struct ieee80211_sub_if_data *sdata;
+	struct rc_pid_info *pinfo = priv;
+	struct sta_info *sta;
+	struct rc_pid_sta_info *spinfo;
+	unsigned long period;
+	struct ieee80211_supported_band *sband;
+
+	sta = sta_info_get(local, hdr->addr1);
+	sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
+
+	if (!sta)
+		return;
+
+	/* Don't update the state if we're not controlling the rate. */
+	sdata = IEEE80211_DEV_TO_SUB_IF(sta->dev);
+	if (sdata->bss && sdata->bss->force_unicast_rateidx > -1) {
+		sta->txrate_idx = sdata->bss->max_ratectrl_rateidx;
+		return;
+	}
+
+	/* Ignore all frames that were sent with a different rate than the rate
+	 * we currently advise mac80211 to use. */
+	if (status->control.tx_rate != &sband->bitrates[sta->txrate_idx])
+		goto ignore;
+
+	spinfo = sta->rate_ctrl_priv;
+	spinfo->tx_num_xmit++;
+
+#ifdef CONFIG_MAC80211_DEBUGFS
+	rate_control_pid_event_tx_status(&spinfo->events, status);
+#endif
+
+	/* We count frames that totally failed to be transmitted as two bad
+	 * frames, those that made it out but had some retries as one good and
+	 * one bad frame. */
+	if (status->excessive_retries) {
+		spinfo->tx_num_failed += 2;
+		spinfo->tx_num_xmit++;
+	} else if (status->retry_count) {
+		spinfo->tx_num_failed++;
+		spinfo->tx_num_xmit++;
+	}
+
+	if (status->excessive_retries) {
+		sta->tx_retry_failed++;
+		sta->tx_num_consecutive_failures++;
+		sta->tx_num_mpdu_fail++;
+	} else {
+		sta->last_ack_rssi[0] = sta->last_ack_rssi[1];
+		sta->last_ack_rssi[1] = sta->last_ack_rssi[2];
+		sta->last_ack_rssi[2] = status->ack_signal;
+		sta->tx_num_consecutive_failures = 0;
+		sta->tx_num_mpdu_ok++;
+	}
+	sta->tx_retry_count += status->retry_count;
+	sta->tx_num_mpdu_fail += status->retry_count;
+
+	/* Update PID controller state. */
+	period = (HZ * pinfo->sampling_period + 500) / 1000;
+	if (!period)
+		period = 1;
+	if (time_after(jiffies, spinfo->last_sample + period))
+		rate_control_pid_sample(pinfo, local, sta);
+
+ignore:
+	sta_info_put(sta);
+}
+
+static void rate_control_pid_get_rate(void *priv, struct net_device *dev,
+				      struct ieee80211_supported_band *sband,
+				      struct sk_buff *skb,
+				      struct rate_selection *sel)
+{
+	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
+	struct ieee80211_sub_if_data *sdata;
+	struct sta_info *sta;
+	int rateidx;
+	u16 fc;
+
+	sta = sta_info_get(local, hdr->addr1);
+
+	/* Send management frames and broadcast/multicast data using lowest
+	 * rate. */
+	fc = le16_to_cpu(hdr->frame_control);
+	if ((fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA ||
+	    is_multicast_ether_addr(hdr->addr1) || !sta) {
+		sel->rate = rate_lowest(local, sband, sta);
+		if (sta)
+			sta_info_put(sta);
+		return;
+	}
+
+	/* If a forced rate is in effect, select it. */
+	sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+	if (sdata->bss && sdata->bss->force_unicast_rateidx > -1)
+		sta->txrate_idx = sdata->bss->force_unicast_rateidx;
+
+	rateidx = sta->txrate_idx;
+
+	if (rateidx >= sband->n_bitrates)
+		rateidx = sband->n_bitrates - 1;
+
+	sta->last_txrate_idx = rateidx;
+
+	sta_info_put(sta);
+
+	sel->rate = &sband->bitrates[rateidx];
+
+#ifdef CONFIG_MAC80211_DEBUGFS
+	rate_control_pid_event_tx_rate(
+		&((struct rc_pid_sta_info *) sta->rate_ctrl_priv)->events,
+		rateidx, sband->bitrates[rateidx].bitrate);
+#endif
+}
+
+static void rate_control_pid_rate_init(void *priv, void *priv_sta,
+					  struct ieee80211_local *local,
+					  struct sta_info *sta)
+{
+	/* TODO: This routine should consider using RSSI from previous packets
+	 * as we need to have IEEE 802.1X auth succeed immediately after assoc..
+	 * Until that method is implemented, we will use the lowest supported
+	 * rate as a workaround. */
+	struct ieee80211_supported_band *sband;
+
+	sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
+	sta->txrate_idx = rate_lowest_index(local, sband, sta);
+}
+
+static void *rate_control_pid_alloc(struct ieee80211_local *local)
+{
+	struct rc_pid_info *pinfo;
+	struct rc_pid_rateinfo *rinfo;
+	struct ieee80211_supported_band *sband;
+	int i, j, tmp;
+	bool s;
+#ifdef CONFIG_MAC80211_DEBUGFS
+	struct rc_pid_debugfs_entries *de;
+#endif
+
+	sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
+
+	pinfo = kmalloc(sizeof(*pinfo), GFP_ATOMIC);
+	if (!pinfo)
+		return NULL;
+
+	/* We can safely assume that sband won't change unless we get
+	 * reinitialized. */
+	rinfo = kmalloc(sizeof(*rinfo) * sband->n_bitrates, GFP_ATOMIC);
+	if (!rinfo) {
+		kfree(pinfo);
+		return NULL;
+	}
+
+	/* Sort the rates. This is optimized for the most common case (i.e.
+	 * almost-sorted CCK+OFDM rates). Kind of bubble-sort with reversed
+	 * mapping too. */
+	for (i = 0; i < sband->n_bitrates; i++) {
+		rinfo[i].index = i;
+		rinfo[i].rev_index = i;
+		if (pinfo->fast_start)
+			rinfo[i].diff = 0;
+		else
+			rinfo[i].diff = i * pinfo->norm_offset;
+	}
+	for (i = 1; i < sband->n_bitrates; i++) {
+		s = 0;
+		for (j = 0; j < sband->n_bitrates - i; j++)
+			if (unlikely(sband->bitrates[rinfo[j].index].bitrate >
+				     sband->bitrates[rinfo[j + 1].index].bitrate)) {
+				tmp = rinfo[j].index;
+				rinfo[j].index = rinfo[j + 1].index;
+				rinfo[j + 1].index = tmp;
+				rinfo[rinfo[j].index].rev_index = j;
+				rinfo[rinfo[j + 1].index].rev_index = j + 1;
+				s = 1;
+			}
+		if (!s)
+			break;
+	}
+
+	pinfo->target = RC_PID_TARGET_PF;
+	pinfo->sampling_period = RC_PID_INTERVAL;
+	pinfo->coeff_p = RC_PID_COEFF_P;
+	pinfo->coeff_i = RC_PID_COEFF_I;
+	pinfo->coeff_d = RC_PID_COEFF_D;
+	pinfo->smoothing_shift = RC_PID_SMOOTHING_SHIFT;
+	pinfo->sharpen_factor = RC_PID_SHARPENING_FACTOR;
+	pinfo->sharpen_duration = RC_PID_SHARPENING_DURATION;
+	pinfo->norm_offset = RC_PID_NORM_OFFSET;
+	pinfo->fast_start = RC_PID_FAST_START;
+	pinfo->rinfo = rinfo;
+	pinfo->oldrate = 0;
+
+#ifdef CONFIG_MAC80211_DEBUGFS
+	de = &pinfo->dentries;
+	de->dir = debugfs_create_dir("rc80211_pid",
+				     local->hw.wiphy->debugfsdir);
+	de->target = debugfs_create_u32("target_pf", S_IRUSR | S_IWUSR,
+					de->dir, &pinfo->target);
+	de->sampling_period = debugfs_create_u32("sampling_period",
+						 S_IRUSR | S_IWUSR, de->dir,
+						 &pinfo->sampling_period);
+	de->coeff_p = debugfs_create_u32("coeff_p", S_IRUSR | S_IWUSR,
+					 de->dir, &pinfo->coeff_p);
+	de->coeff_i = debugfs_create_u32("coeff_i", S_IRUSR | S_IWUSR,
+					 de->dir, &pinfo->coeff_i);
+	de->coeff_d = debugfs_create_u32("coeff_d", S_IRUSR | S_IWUSR,
+					 de->dir, &pinfo->coeff_d);
+	de->smoothing_shift = debugfs_create_u32("smoothing_shift",
+						 S_IRUSR | S_IWUSR, de->dir,
+						 &pinfo->smoothing_shift);
+	de->sharpen_factor = debugfs_create_u32("sharpen_factor",
+					       S_IRUSR | S_IWUSR, de->dir,
+					       &pinfo->sharpen_factor);
+	de->sharpen_duration = debugfs_create_u32("sharpen_duration",
+						  S_IRUSR | S_IWUSR, de->dir,
+						  &pinfo->sharpen_duration);
+	de->norm_offset = debugfs_create_u32("norm_offset",
+					     S_IRUSR | S_IWUSR, de->dir,
+					     &pinfo->norm_offset);
+	de->fast_start = debugfs_create_bool("fast_start",
+					     S_IRUSR | S_IWUSR, de->dir,
+					     &pinfo->fast_start);
+#endif
+
+	return pinfo;
+}
+
+static void rate_control_pid_free(void *priv)
+{
+	struct rc_pid_info *pinfo = priv;
+#ifdef CONFIG_MAC80211_DEBUGFS
+	struct rc_pid_debugfs_entries *de = &pinfo->dentries;
+
+	debugfs_remove(de->fast_start);
+	debugfs_remove(de->norm_offset);
+	debugfs_remove(de->sharpen_duration);
+	debugfs_remove(de->sharpen_factor);
+	debugfs_remove(de->smoothing_shift);
+	debugfs_remove(de->coeff_d);
+	debugfs_remove(de->coeff_i);
+	debugfs_remove(de->coeff_p);
+	debugfs_remove(de->sampling_period);
+	debugfs_remove(de->target);
+	debugfs_remove(de->dir);
+#endif
+
+	kfree(pinfo->rinfo);
+	kfree(pinfo);
+}
+
+static void rate_control_pid_clear(void *priv)
+{
+}
+
+static void *rate_control_pid_alloc_sta(void *priv, gfp_t gfp)
+{
+	struct rc_pid_sta_info *spinfo;
+
+	spinfo = kzalloc(sizeof(*spinfo), gfp);
+	if (spinfo == NULL)
+		return NULL;
+
+	spinfo->last_sample = jiffies;
+
+#ifdef CONFIG_MAC80211_DEBUGFS
+	spin_lock_init(&spinfo->events.lock);
+	init_waitqueue_head(&spinfo->events.waitqueue);
+#endif
+
+	return spinfo;
+}
+
+static void rate_control_pid_free_sta(void *priv, void *priv_sta)
+{
+	struct rc_pid_sta_info *spinfo = priv_sta;
+	kfree(spinfo);
+}
+
+static struct rate_control_ops mac80211_rcpid = {
+	.name = "pid",
+	.tx_status = rate_control_pid_tx_status,
+	.get_rate = rate_control_pid_get_rate,
+	.rate_init = rate_control_pid_rate_init,
+	.clear = rate_control_pid_clear,
+	.alloc = rate_control_pid_alloc,
+	.free = rate_control_pid_free,
+	.alloc_sta = rate_control_pid_alloc_sta,
+	.free_sta = rate_control_pid_free_sta,
+#ifdef CONFIG_MAC80211_DEBUGFS
+	.add_sta_debugfs = rate_control_pid_add_sta_debugfs,
+	.remove_sta_debugfs = rate_control_pid_remove_sta_debugfs,
+#endif
+};
+
+MODULE_DESCRIPTION("PID controller based rate control algorithm");
+MODULE_AUTHOR("Stefano Brivio");
+MODULE_AUTHOR("Mattias Nissler");
+MODULE_LICENSE("GPL");
+
+int __init rc80211_pid_init(void)
+{
+	return ieee80211_rate_control_register(&mac80211_rcpid);
+}
+
+void rc80211_pid_exit(void)
+{
+	ieee80211_rate_control_unregister(&mac80211_rcpid);
+}
+
+#ifdef CONFIG_MAC80211_RC_PID_MODULE
+module_init(rc80211_pid_init);
+module_exit(rc80211_pid_exit);
+#endif
diff --git a/package/mac80211/src/net/mac80211/rc80211_pid_debugfs.c b/package/mac80211/src/net/mac80211/rc80211_pid_debugfs.c
new file mode 100644
index 0000000000..88b8dc9999
--- /dev/null
+++ b/package/mac80211/src/net/mac80211/rc80211_pid_debugfs.c
@@ -0,0 +1,223 @@
+/*
+ * Copyright 2007, Mattias Nissler <mattias.nissler@gmx.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/spinlock.h>
+#include <linux/poll.h>
+#include <linux/netdevice.h>
+#include <linux/types.h>
+#include <linux/skbuff.h>
+
+#include <net/mac80211.h>
+#include "ieee80211_rate.h"
+
+#include "rc80211_pid.h"
+
+static void rate_control_pid_event(struct rc_pid_event_buffer *buf,
+				   enum rc_pid_event_type type,
+				   union rc_pid_event_data *data)
+{
+	struct rc_pid_event *ev;
+	unsigned long status;
+
+	spin_lock_irqsave(&buf->lock, status);
+	ev = &(buf->ring[buf->next_entry]);
+	buf->next_entry = (buf->next_entry + 1) % RC_PID_EVENT_RING_SIZE;
+
+	ev->timestamp = jiffies;
+	ev->id = buf->ev_count++;
+	ev->type = type;
+	ev->data = *data;
+
+	spin_unlock_irqrestore(&buf->lock, status);
+
+	wake_up_all(&buf->waitqueue);
+}
+
+void rate_control_pid_event_tx_status(struct rc_pid_event_buffer *buf,
+					     struct ieee80211_tx_status *stat)
+{
+	union rc_pid_event_data evd;
+
+	memcpy(&evd.tx_status, stat, sizeof(struct ieee80211_tx_status));
+	rate_control_pid_event(buf, RC_PID_EVENT_TYPE_TX_STATUS, &evd);
+}
+
+void rate_control_pid_event_rate_change(struct rc_pid_event_buffer *buf,
+					       int index, int rate)
+{
+	union rc_pid_event_data evd;
+
+	evd.index = index;
+	evd.rate = rate;
+	rate_control_pid_event(buf, RC_PID_EVENT_TYPE_RATE_CHANGE, &evd);
+}
+
+void rate_control_pid_event_tx_rate(struct rc_pid_event_buffer *buf,
+					   int index, int rate)
+{
+	union rc_pid_event_data evd;
+
+	evd.index = index;
+	evd.rate = rate;
+	rate_control_pid_event(buf, RC_PID_EVENT_TYPE_TX_RATE, &evd);
+}
+
+void rate_control_pid_event_pf_sample(struct rc_pid_event_buffer *buf,
+					     s32 pf_sample, s32 prop_err,
+					     s32 int_err, s32 der_err)
+{
+	union rc_pid_event_data evd;
+
+	evd.pf_sample = pf_sample;
+	evd.prop_err = prop_err;
+	evd.int_err = int_err;
+	evd.der_err = der_err;
+	rate_control_pid_event(buf, RC_PID_EVENT_TYPE_PF_SAMPLE, &evd);
+}
+
+static int rate_control_pid_events_open(struct inode *inode, struct file *file)
+{
+	struct rc_pid_sta_info *sinfo = inode->i_private;
+	struct rc_pid_event_buffer *events = &sinfo->events;
+	struct rc_pid_events_file_info *file_info;
+	unsigned int status;
+
+	/* Allocate a state struct */
+	file_info = kmalloc(sizeof(*file_info), GFP_KERNEL);
+	if (file_info == NULL)
+		return -ENOMEM;
+
+	spin_lock_irqsave(&events->lock, status);
+
+	file_info->next_entry = events->next_entry;
+	file_info->events = events;
+
+	spin_unlock_irqrestore(&events->lock, status);
+
+	file->private_data = file_info;
+
+	return 0;
+}
+
+static int rate_control_pid_events_release(struct inode *inode,
+					   struct file *file)
+{
+	struct rc_pid_events_file_info *file_info = file->private_data;
+
+	kfree(file_info);
+
+	return 0;
+}
+
+static unsigned int rate_control_pid_events_poll(struct file *file,
+						 poll_table *wait)
+{
+	struct rc_pid_events_file_info *file_info = file->private_data;
+
+	poll_wait(file, &file_info->events->waitqueue, wait);
+
+	return POLLIN | POLLRDNORM;
+}
+
+#define RC_PID_PRINT_BUF_SIZE 64
+
+static ssize_t rate_control_pid_events_read(struct file *file, char __user *buf,
+					    size_t length, loff_t *offset)
+{
+	struct rc_pid_events_file_info *file_info = file->private_data;
+	struct rc_pid_event_buffer *events = file_info->events;
+	struct rc_pid_event *ev;
+	char pb[RC_PID_PRINT_BUF_SIZE];
+	int ret;
+	int p;
+	unsigned int status;
+
+	/* Check if there is something to read. */
+	if (events->next_entry == file_info->next_entry) {
+		if (file->f_flags & O_NONBLOCK)
+			return -EAGAIN;
+
+		/* Wait */
+		ret = wait_event_interruptible(events->waitqueue,
+				events->next_entry != file_info->next_entry);
+
+		if (ret)
+			return ret;
+	}
+
+	/* Write out one event per call. I don't care whether it's a little
+	 * inefficient, this is debugging code anyway. */
+	spin_lock_irqsave(&events->lock, status);
+
+	/* Get an event */
+	ev = &(events->ring[file_info->next_entry]);
+	file_info->next_entry = (file_info->next_entry + 1) %
+				RC_PID_EVENT_RING_SIZE;
+
+	/* Print information about the event. Note that userpace needs to
+	 * provide large enough buffers. */
+	length = length < RC_PID_PRINT_BUF_SIZE ?
+		 length : RC_PID_PRINT_BUF_SIZE;
+	p = snprintf(pb, length, "%u %lu ", ev->id, ev->timestamp);
+	switch (ev->type) {
+	case RC_PID_EVENT_TYPE_TX_STATUS:
+		p += snprintf(pb + p, length - p, "tx_status %u %u",
+			      ev->data.tx_status.excessive_retries,
+			      ev->data.tx_status.retry_count);
+		break;
+	case RC_PID_EVENT_TYPE_RATE_CHANGE:
+		p += snprintf(pb + p, length - p, "rate_change %d %d",
+			      ev->data.index, ev->data.rate);
+		break;
+	case RC_PID_EVENT_TYPE_TX_RATE:
+		p += snprintf(pb + p, length - p, "tx_rate %d %d",
+			      ev->data.index, ev->data.rate);
+		break;
+	case RC_PID_EVENT_TYPE_PF_SAMPLE:
+		p += snprintf(pb + p, length - p,
+			      "pf_sample %d %d %d %d",
+			      ev->data.pf_sample, ev->data.prop_err,
+			      ev->data.int_err, ev->data.der_err);
+		break;
+	}
+	p += snprintf(pb + p, length - p, "\n");
+
+	spin_unlock_irqrestore(&events->lock, status);
+
+	if (copy_to_user(buf, pb, p))
+		return -EFAULT;
+
+	return p;
+}
+
+#undef RC_PID_PRINT_BUF_SIZE
+
+static struct file_operations rc_pid_fop_events = {
+	.owner = THIS_MODULE,
+	.read = rate_control_pid_events_read,
+	.poll = rate_control_pid_events_poll,
+	.open = rate_control_pid_events_open,
+	.release = rate_control_pid_events_release,
+};
+
+void rate_control_pid_add_sta_debugfs(void *priv, void *priv_sta,
+					     struct dentry *dir)
+{
+	struct rc_pid_sta_info *spinfo = priv_sta;
+
+	spinfo->events_entry = debugfs_create_file("rc_pid_events", S_IRUGO,
+						   dir, spinfo,
+						   &rc_pid_fop_events);
+}
+
+void rate_control_pid_remove_sta_debugfs(void *priv, void *priv_sta)
+{
+	struct rc_pid_sta_info *spinfo = priv_sta;
+
+	debugfs_remove(spinfo->events_entry);
+}
diff --git a/package/mac80211/src/net/mac80211/rc80211_simple.c b/package/mac80211/src/net/mac80211/rc80211_simple.c
index ef91ce428a..c4678905a1 100644
--- a/package/mac80211/src/net/mac80211/rc80211_simple.c
+++ b/package/mac80211/src/net/mac80211/rc80211_simple.c
@@ -7,13 +7,13 @@
  * published by the Free Software Foundation.
  */
 
-#include <linux/module.h>
 #include <linux/init.h>
 #include <linux/netdevice.h>
 #include <linux/types.h>
 #include <linux/slab.h>
 #include <linux/skbuff.h>
 #include <linux/compiler.h>
+#include <linux/module.h>
 
 #include <net/mac80211.h>
 #include "ieee80211_i.h"
@@ -24,19 +24,19 @@
 /* This is a minimal implementation of TX rate controlling that can be used
  * as the default when no improved mechanisms are available. */
 
+#define RATE_CONTROL_NUM_DOWN 20
+#define RATE_CONTROL_NUM_UP   15
 
 #define RATE_CONTROL_EMERG_DEC 2
 #define RATE_CONTROL_INTERVAL (HZ / 20)
 #define RATE_CONTROL_MIN_TX 10
 
-MODULE_ALIAS("rc80211_default");
-
 static void rate_control_rate_inc(struct ieee80211_local *local,
 				  struct sta_info *sta)
 {
 	struct ieee80211_sub_if_data *sdata;
-	struct ieee80211_hw_mode *mode;
-	int i = sta->txrate;
+	struct ieee80211_supported_band *sband;
+	int i = sta->txrate_idx;
 	int maxrate;
 
 	sdata = IEEE80211_DEV_TO_SUB_IF(sta->dev);
@@ -45,18 +45,17 @@ static void rate_control_rate_inc(struct ieee80211_local *local,
 		return;
 	}
 
-	mode = local->oper_hw_mode;
+	sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
 	maxrate = sdata->bss ? sdata->bss->max_ratectrl_rateidx : -1;
 
-	if (i > mode->num_rates)
-		i = mode->num_rates - 2;
+	if (i > sband->n_bitrates)
+		i = sband->n_bitrates - 2;
 
-	while (i + 1 < mode->num_rates) {
+	while (i + 1 < sband->n_bitrates) {
 		i++;
-		if (sta->supp_rates & BIT(i) &&
-		    mode->rates[i].flags & IEEE80211_RATE_SUPPORTED &&
+		if (rate_supported(sta, sband->band, i) &&
 		    (maxrate < 0 || i <= maxrate)) {
-			sta->txrate = i;
+			sta->txrate_idx = i;
 			break;
 		}
 	}
@@ -67,8 +66,8 @@ static void rate_control_rate_dec(struct ieee80211_local *local,
 				  struct sta_info *sta)
 {
 	struct ieee80211_sub_if_data *sdata;
-	struct ieee80211_hw_mode *mode;
-	int i = sta->txrate;
+	struct ieee80211_supported_band *sband;
+	int i = sta->txrate_idx;
 
 	sdata = IEEE80211_DEV_TO_SUB_IF(sta->dev);
 	if (sdata->bss && sdata->bss->force_unicast_rateidx > -1) {
@@ -76,40 +75,19 @@ static void rate_control_rate_dec(struct ieee80211_local *local,
 		return;
 	}
 
-	mode = local->oper_hw_mode;
-	if (i > mode->num_rates)
-		i = mode->num_rates;
+	sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
+	if (i > sband->n_bitrates)
+		i = sband->n_bitrates;
 
 	while (i > 0) {
 		i--;
-		if (sta->supp_rates & BIT(i) &&
-		    mode->rates[i].flags & IEEE80211_RATE_SUPPORTED) {
-			sta->txrate = i;
+		if (rate_supported(sta, sband->band, i)) {
+			sta->txrate_idx = i;
 			break;
 		}
 	}
 }
 
-
-static struct ieee80211_rate *
-rate_control_lowest_rate(struct ieee80211_local *local,
-			 struct ieee80211_hw_mode *mode)
-{
-	int i;
-
-	for (i = 0; i < mode->num_rates; i++) {
-		struct ieee80211_rate *rate = &mode->rates[i];
-
-		if (rate->flags & IEEE80211_RATE_SUPPORTED)
-			return rate;
-	}
-
-	printk(KERN_DEBUG "rate_control_lowest_rate - no supported rates "
-	       "found\n");
-	return &mode->rates[0];
-}
-
-
 struct global_rate_control {
 	int dummy;
 };
@@ -188,7 +166,7 @@ static void rate_control_simple_tx_status(void *priv, struct net_device *dev,
 		} else if (per_failed < RATE_CONTROL_NUM_UP) {
 			rate_control_rate_inc(local, sta);
 		}
-		srctrl->tx_avg_rate_sum += status->control.rate->rate;
+		srctrl->tx_avg_rate_sum += status->control.tx_rate->bitrate;
 		srctrl->tx_avg_rate_num++;
 		srctrl->tx_num_failures = 0;
 		srctrl->tx_num_xmit = 0;
@@ -201,9 +179,10 @@ static void rate_control_simple_tx_status(void *priv, struct net_device *dev,
 		srctrl->avg_rate_update = jiffies;
 		if (srctrl->tx_avg_rate_num > 0) {
 #ifdef CONFIG_MAC80211_VERBOSE_DEBUG
-			printk(KERN_DEBUG "%s: STA " MAC_FMT " Average rate: "
+			DECLARE_MAC_BUF(mac);
+			printk(KERN_DEBUG "%s: STA %s Average rate: "
 			       "%d (%d/%d)\n",
-			       dev->name, MAC_ARG(sta->addr),
+			       dev->name, print_mac(mac, sta->addr),
 			       srctrl->tx_avg_rate_sum /
 			       srctrl->tx_avg_rate_num,
 			       srctrl->tx_avg_rate_sum,
@@ -218,56 +197,47 @@ static void rate_control_simple_tx_status(void *priv, struct net_device *dev,
 }
 
 
-static struct ieee80211_rate *
+static void
 rate_control_simple_get_rate(void *priv, struct net_device *dev,
+			     struct ieee80211_supported_band *sband,
 			     struct sk_buff *skb,
-			     struct rate_control_extra *extra)
+			     struct rate_selection *sel)
 {
 	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
-	struct ieee80211_sub_if_data *sdata;
 	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
-	struct ieee80211_hw_mode *mode = extra->mode;
+	struct ieee80211_sub_if_data *sdata;
 	struct sta_info *sta;
-	int rateidx, nonerp_idx;
+	int rateidx;
 	u16 fc;
 
-	memset(extra, 0, sizeof(*extra));
+	sta = sta_info_get(local, hdr->addr1);
 
+	/* Send management frames and broadcast/multicast data using lowest
+	 * rate. */
 	fc = le16_to_cpu(hdr->frame_control);
 	if ((fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA ||
-	    (hdr->addr1[0] & 0x01)) {
-		/* Send management frames and broadcast/multicast data using
-		 * lowest rate. */
-		/* TODO: this could probably be improved.. */
-		return rate_control_lowest_rate(local, mode);
+	    is_multicast_ether_addr(hdr->addr1) || !sta) {
+		sel->rate = rate_lowest(local, sband, sta);
+		if (sta)
+			sta_info_put(sta);
+		return;
 	}
 
-	sta = sta_info_get(local, hdr->addr1);
-
-	if (!sta)
-		return rate_control_lowest_rate(local, mode);
-
+	/* If a forced rate is in effect, select it. */
 	sdata = IEEE80211_DEV_TO_SUB_IF(dev);
 	if (sdata->bss && sdata->bss->force_unicast_rateidx > -1)
-		sta->txrate = sdata->bss->force_unicast_rateidx;
+		sta->txrate_idx = sdata->bss->force_unicast_rateidx;
 
-	rateidx = sta->txrate;
+	rateidx = sta->txrate_idx;
 
-	if (rateidx >= mode->num_rates)
-		rateidx = mode->num_rates - 1;
+	if (rateidx >= sband->n_bitrates)
+		rateidx = sband->n_bitrates - 1;
 
-	sta->last_txrate = rateidx;
-	nonerp_idx = rateidx;
-	while (nonerp_idx > 0 &&
-	       ((mode->rates[nonerp_idx].flags & IEEE80211_RATE_ERP) ||
-		!(mode->rates[nonerp_idx].flags & IEEE80211_RATE_SUPPORTED) ||
-		!(sta->supp_rates & BIT(nonerp_idx))))
-		nonerp_idx--;
-	extra->nonerp = &mode->rates[nonerp_idx];
+	sta->last_txrate_idx = rateidx;
 
 	sta_info_put(sta);
 
-	return &mode->rates[rateidx];
+	sel->rate = &sband->bitrates[rateidx];
 }
 
 
@@ -275,21 +245,15 @@ static void rate_control_simple_rate_init(void *priv, void *priv_sta,
 					  struct ieee80211_local *local,
 					  struct sta_info *sta)
 {
-	struct ieee80211_hw_mode *mode;
-	int i;
-	sta->txrate = 0;
-	mode = local->oper_hw_mode;
+	struct ieee80211_supported_band *sband;
+
+	sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
+
 	/* TODO: This routine should consider using RSSI from previous packets
 	 * as we need to have IEEE 802.1X auth succeed immediately after assoc..
 	 * Until that method is implemented, we will use the lowest supported rate
 	 * as a workaround, */
-	for (i = 0; i < mode->num_rates; i++) {
-		if ((sta->supp_rates & BIT(i)) &&
-		    (mode->rates[i].flags & IEEE80211_RATE_SUPPORTED)) {
-			sta->txrate = i;
-			break;
-		}
-	}
+	sta->txrate_idx = rate_lowest_index(local, sband, sta);
 }
 
 
@@ -393,8 +357,7 @@ static void rate_control_simple_remove_sta_debugfs(void *priv, void *priv_sta)
 }
 #endif
 
-static struct rate_control_ops rate_control_simple = {
-	.module = THIS_MODULE,
+static struct rate_control_ops mac80211_rcsimple = {
 	.name = "simple",
 	.tx_status = rate_control_simple_tx_status,
 	.get_rate = rate_control_simple_get_rate,
@@ -410,21 +373,20 @@ static struct rate_control_ops rate_control_simple = {
 #endif
 };
 
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Simple rate control algorithm");
 
-static int __init rate_control_simple_init(void)
+int __init rc80211_simple_init(void)
 {
-	return ieee80211_rate_control_register(&rate_control_simple);
+	return ieee80211_rate_control_register(&mac80211_rcsimple);
 }
 
-
-static void __exit rate_control_simple_exit(void)
+void rc80211_simple_exit(void)
 {
-	ieee80211_rate_control_unregister(&rate_control_simple);
+	ieee80211_rate_control_unregister(&mac80211_rcsimple);
 }
 
-
-subsys_initcall(rate_control_simple_init);
-module_exit(rate_control_simple_exit);
-
-MODULE_DESCRIPTION("Simple rate control algorithm for ieee80211");
-MODULE_LICENSE("GPL");
+#ifdef CONFIG_MAC80211_RC_SIMPLE_MODULE
+module_init(rc80211_simple_init);
+module_exit(rc80211_simple_exit);
+#endif
diff --git a/package/mac80211/src/net/mac80211/regdomain.c b/package/mac80211/src/net/mac80211/regdomain.c
deleted file mode 100644
index f42678fa62..0000000000
--- a/package/mac80211/src/net/mac80211/regdomain.c
+++ /dev/null
@@ -1,152 +0,0 @@
-/*
- * Copyright 2002-2005, Instant802 Networks, Inc.
- * Copyright 2005-2006, Devicescape Software, Inc.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-/*
- * This regulatory domain control implementation is known to be incomplete
- * and confusing. mac80211 regulatory domain control will be significantly
- * reworked in the not-too-distant future.
- *
- * For now, drivers wishing to control which channels are and aren't available
- * are advised as follows:
- *  - set the IEEE80211_HW_DEFAULT_REG_DOMAIN_CONFIGURED flag
- *  - continue to include *ALL* possible channels in the modes registered
- *    through ieee80211_register_hwmode()
- *  - for each allowable ieee80211_channel structure registered in the above
- *    call, set the flag member to some meaningful value such as
- *    IEEE80211_CHAN_W_SCAN | IEEE80211_CHAN_W_ACTIVE_SCAN |
- *    IEEE80211_CHAN_W_IBSS.
- *  - leave flag as 0 for non-allowable channels
- *
- * The usual implementation is for a driver to read a device EEPROM to
- * determine which regulatory domain it should be operating under, then
- * looking up the allowable channels in a driver-local table, then performing
- * the above.
- */
-
-#include <linux/module.h>
-#include <linux/netdevice.h>
-#include <net/mac80211.h>
-#include "ieee80211_i.h"
-
-static int ieee80211_regdom = 0x10; /* FCC */
-module_param(ieee80211_regdom, int, 0444);
-MODULE_PARM_DESC(ieee80211_regdom, "IEEE 802.11 regulatory domain; 64=MKK");
-
-/*
- * If firmware is upgraded by the vendor, additional channels can be used based
- * on the new Japanese regulatory rules. This is indicated by setting
- * ieee80211_japan_5ghz module parameter to one when loading the 80211 kernel
- * module.
- */
-static int ieee80211_japan_5ghz /* = 0 */;
-module_param(ieee80211_japan_5ghz, int, 0444);
-MODULE_PARM_DESC(ieee80211_japan_5ghz, "Vendor-updated firmware for 5 GHz");
-
-
-struct ieee80211_channel_range {
-	short start_freq;
-	short end_freq;
-	unsigned char power_level;
-	unsigned char antenna_max;
-};
-
-static const struct ieee80211_channel_range ieee80211_fcc_channels[] = {
-	{ 2412, 2462, 27, 6 } /* IEEE 802.11b/g, channels 1..11 */,
-	{ 5180, 5240, 17, 6 } /* IEEE 802.11a, channels 36..48 */,
-	{ 5260, 5320, 23, 6 } /* IEEE 802.11a, channels 52..64 */,
-	{ 5745, 5825, 30, 6 } /* IEEE 802.11a, channels 149..165, outdoor */,
-	{ 0 }
-};
-
-static const struct ieee80211_channel_range ieee80211_mkk_channels[] = {
-	{ 2412, 2472, 20, 6 } /* IEEE 802.11b/g, channels 1..13 */,
-	{ 5170, 5240, 20, 6 } /* IEEE 802.11a, channels 34..48 */,
-	{ 5260, 5320, 20, 6 } /* IEEE 802.11a, channels 52..64 */,
-	{ 0 }
-};
-
-
-static const struct ieee80211_channel_range *channel_range =
-	ieee80211_fcc_channels;
-
-
-static void ieee80211_unmask_channel(int mode, struct ieee80211_channel *chan)
-{
-	int i;
-
-	chan->flag = 0;
-
-	for (i = 0; channel_range[i].start_freq; i++) {
-		const struct ieee80211_channel_range *r = &channel_range[i];
-		if (r->start_freq <= chan->freq && r->end_freq >= chan->freq) {
-			if (ieee80211_regdom == 64 && !ieee80211_japan_5ghz &&
-			    chan->freq >= 5260 && chan->freq <= 5320) {
-				/*
-				 * Skip new channels in Japan since the
-				 * firmware was not marked having been upgraded
-				 * by the vendor.
-				 */
-				continue;
-			}
-
-			if (ieee80211_regdom == 0x10 &&
-			    (chan->freq == 5190 || chan->freq == 5210 ||
-			     chan->freq == 5230)) {
-				    /* Skip MKK channels when in FCC domain. */
-				    continue;
-			}
-
-			chan->flag |= IEEE80211_CHAN_W_SCAN |
-				IEEE80211_CHAN_W_ACTIVE_SCAN |
-				IEEE80211_CHAN_W_IBSS;
-			chan->power_level = r->power_level;
-			chan->antenna_max = r->antenna_max;
-
-			if (ieee80211_regdom == 64 &&
-			    (chan->freq == 5170 || chan->freq == 5190 ||
-			     chan->freq == 5210 || chan->freq == 5230)) {
-				/*
-				 * New regulatory rules in Japan have backwards
-				 * compatibility with old channels in 5.15-5.25
-				 * GHz band, but the station is not allowed to
-				 * use active scan on these old channels.
-				 */
-				chan->flag &= ~IEEE80211_CHAN_W_ACTIVE_SCAN;
-			}
-
-			if (ieee80211_regdom == 64 &&
-			    (chan->freq == 5260 || chan->freq == 5280 ||
-			     chan->freq == 5300 || chan->freq == 5320)) {
-				/*
-				 * IBSS is not allowed on 5.25-5.35 GHz band
-				 * due to radar detection requirements.
-				 */
-				chan->flag &= ~IEEE80211_CHAN_W_IBSS;
-			}
-
-			break;
-		}
-	}
-}
-
-
-void ieee80211_set_default_regdomain(struct ieee80211_hw_mode *mode)
-{
-	int c;
-	for (c = 0; c < mode->num_channels; c++)
-		ieee80211_unmask_channel(mode->mode, &mode->channels[c]);
-}
-
-
-void ieee80211_regdomain_init(void)
-{
-	if (ieee80211_regdom == 0x40)
-		channel_range = ieee80211_mkk_channels;
-}
-
diff --git a/package/mac80211/src/net/mac80211/rx.c b/package/mac80211/src/net/mac80211/rx.c
index 064924cb28..943ba90829 100644
--- a/package/mac80211/src/net/mac80211/rx.c
+++ b/package/mac80211/src/net/mac80211/rx.c
@@ -24,6 +24,10 @@
 #include "tkip.h"
 #include "wme.h"
 
+u8 ieee80211_sta_manage_reorder_buf(struct ieee80211_hw *hw,
+				struct tid_ampdu_rx *tid_agg_rx,
+				struct sk_buff *skb, u16 mpdu_seq_num,
+				int bar_req);
 /*
  * monitor mode reception
  *
@@ -61,8 +65,12 @@ static inline int should_drop_frame(struct ieee80211_rx_status *status,
 		return 1;
 	if (unlikely(skb->len < 16 + present_fcs_len + radiotap_len))
 		return 1;
-	if ((hdr->frame_control & cpu_to_le16(IEEE80211_FCTL_FTYPE)) ==
-			cpu_to_le16(IEEE80211_FTYPE_CTL))
+	if (((hdr->frame_control & cpu_to_le16(IEEE80211_FCTL_FTYPE)) ==
+			cpu_to_le16(IEEE80211_FTYPE_CTL)) &&
+	    ((hdr->frame_control & cpu_to_le16(IEEE80211_FCTL_STYPE)) !=
+			cpu_to_le16(IEEE80211_STYPE_PSPOLL)) &&
+	    ((hdr->frame_control & cpu_to_le16(IEEE80211_FCTL_STYPE)) !=
+			cpu_to_le16(IEEE80211_STYPE_BACK_REQ)))
 		return 1;
 	return 0;
 }
@@ -74,13 +82,14 @@ static inline int should_drop_frame(struct ieee80211_rx_status *status,
  */
 static struct sk_buff *
 ieee80211_rx_monitor(struct ieee80211_local *local, struct sk_buff *origskb,
-		     struct ieee80211_rx_status *status)
+		     struct ieee80211_rx_status *status,
+		     struct ieee80211_rate *rate)
 {
 	struct ieee80211_sub_if_data *sdata;
-	struct ieee80211_rate *rate;
 	int needed_headroom = 0;
-	struct ieee80211_rtap_hdr {
-		struct ieee80211_radiotap_header hdr;
+	struct ieee80211_radiotap_header *rthdr;
+	__le64 *rttsft = NULL;
+	struct ieee80211_rtap_fixed_data {
 		u8 flags;
 		u8 rate;
 		__le16 chan_freq;
@@ -88,7 +97,7 @@ ieee80211_rx_monitor(struct ieee80211_local *local, struct sk_buff *origskb,
 		u8 antsignal;
 		u8 padding_for_rxflags;
 		__le16 rx_flags;
-	} __attribute__ ((packed)) *rthdr;
+	} __attribute__ ((packed)) *rtfixed;
 	struct sk_buff *skb, *skb2;
 	struct net_device *prev_dev = NULL;
 	int present_fcs_len = 0;
@@ -105,7 +114,8 @@ ieee80211_rx_monitor(struct ieee80211_local *local, struct sk_buff *origskb,
 	if (status->flag & RX_FLAG_RADIOTAP)
 		rtap_len = ieee80211_get_radiotap_len(origskb->data);
 	else
-		needed_headroom = sizeof(*rthdr);
+		/* room for radiotap header, always present fields and TSFT */
+		needed_headroom = sizeof(*rthdr) + sizeof(*rtfixed) + 8;
 
 	if (local->hw.flags & IEEE80211_HW_RX_INCLUDES_FCS)
 		present_fcs_len = FCS_LEN;
@@ -133,7 +143,7 @@ ieee80211_rx_monitor(struct ieee80211_local *local, struct sk_buff *origskb,
 		 * them allocate enough headroom to start with.
 		 */
 		if (skb_headroom(skb) < needed_headroom &&
-		    pskb_expand_head(skb, sizeof(*rthdr), 0, GFP_ATOMIC)) {
+		    pskb_expand_head(skb, needed_headroom, 0, GFP_ATOMIC)) {
 			dev_kfree_skb(skb);
 			return NULL;
 		}
@@ -152,45 +162,56 @@ ieee80211_rx_monitor(struct ieee80211_local *local, struct sk_buff *origskb,
 
 	/* if necessary, prepend radiotap information */
 	if (!(status->flag & RX_FLAG_RADIOTAP)) {
+		rtfixed = (void *) skb_push(skb, sizeof(*rtfixed));
+		rtap_len = sizeof(*rthdr) + sizeof(*rtfixed);
+		if (status->flag & RX_FLAG_TSFT) {
+			rttsft = (void *) skb_push(skb, sizeof(*rttsft));
+			rtap_len += 8;
+		}
 		rthdr = (void *) skb_push(skb, sizeof(*rthdr));
 		memset(rthdr, 0, sizeof(*rthdr));
-		rthdr->hdr.it_len = cpu_to_le16(sizeof(*rthdr));
-		rthdr->hdr.it_present =
+		memset(rtfixed, 0, sizeof(*rtfixed));
+		rthdr->it_present =
 			cpu_to_le32((1 << IEEE80211_RADIOTAP_FLAGS) |
 				    (1 << IEEE80211_RADIOTAP_RATE) |
 				    (1 << IEEE80211_RADIOTAP_CHANNEL) |
 				    (1 << IEEE80211_RADIOTAP_DB_ANTSIGNAL) |
 				    (1 << IEEE80211_RADIOTAP_RX_FLAGS));
-		rthdr->flags = local->hw.flags & IEEE80211_HW_RX_INCLUDES_FCS ?
-			       IEEE80211_RADIOTAP_F_FCS : 0;
+		rtfixed->flags = 0;
+		if (local->hw.flags & IEEE80211_HW_RX_INCLUDES_FCS)
+			rtfixed->flags |= IEEE80211_RADIOTAP_F_FCS;
+
+		if (rttsft) {
+			*rttsft = cpu_to_le64(status->mactime);
+			rthdr->it_present |=
+				cpu_to_le32(1 << IEEE80211_RADIOTAP_TSFT);
+		}
 
 		/* FIXME: when radiotap gets a 'bad PLCP' flag use it here */
-		rthdr->rx_flags = 0;
+		rtfixed->rx_flags = 0;
 		if (status->flag &
 		    (RX_FLAG_FAILED_FCS_CRC | RX_FLAG_FAILED_PLCP_CRC))
-			rthdr->rx_flags |=
+			rtfixed->rx_flags |=
 				cpu_to_le16(IEEE80211_RADIOTAP_F_RX_BADFCS);
 
-		rate = ieee80211_get_rate(local, status->phymode,
-					  status->rate);
-		if (rate)
-			rthdr->rate = rate->rate / 5;
+		rtfixed->rate = rate->bitrate / 5;
 
-		rthdr->chan_freq = cpu_to_le16(status->freq);
+		rtfixed->chan_freq = cpu_to_le16(status->freq);
 
-		if (status->phymode == MODE_IEEE80211A)
-			rthdr->chan_flags =
+		if (status->band == IEEE80211_BAND_5GHZ)
+			rtfixed->chan_flags =
 				cpu_to_le16(IEEE80211_CHAN_OFDM |
 					    IEEE80211_CHAN_5GHZ);
 		else
-			rthdr->chan_flags =
+			rtfixed->chan_flags =
 				cpu_to_le16(IEEE80211_CHAN_DYN |
 					    IEEE80211_CHAN_2GHZ);
 
-		rthdr->antsignal = status->ssi;
+		rtfixed->antsignal = status->ssi;
+		rthdr->it_len = cpu_to_le16(rtap_len);
 	}
 
-	skb_set_mac_header(skb, 0);
+	skb_reset_mac_header(skb);
 	skb->ip_summed = CHECKSUM_UNNECESSARY;
 	skb->pkt_type = PACKET_OTHERHOST;
 	skb->protocol = htons(ETH_P_802_2);
@@ -199,7 +220,10 @@ ieee80211_rx_monitor(struct ieee80211_local *local, struct sk_buff *origskb,
 		if (!netif_running(sdata->dev))
 			continue;
 
-		if (sdata->type != IEEE80211_IF_TYPE_MNTR)
+		if (sdata->vif.type != IEEE80211_IF_TYPE_MNTR)
+			continue;
+
+		if (sdata->u.mntr_flags & MONITOR_FLAG_COOK_FRAMES)
 			continue;
 
 		if (prev_dev) {
@@ -225,15 +249,7 @@ ieee80211_rx_monitor(struct ieee80211_local *local, struct sk_buff *origskb,
 }
 
 
-/* pre-rx handlers
- *
- * these don't have dev/sdata fields in the rx data
- * The sta value should also not be used because it may
- * be NULL even though a STA (in IBSS mode) will be added.
- */
-
-static ieee80211_txrx_result
-ieee80211_rx_h_parse_qos(struct ieee80211_txrx_data *rx)
+static void ieee80211_parse_qos(struct ieee80211_txrx_data *rx)
 {
 	u8 *data = rx->skb->data;
 	int tid;
@@ -243,6 +259,10 @@ ieee80211_rx_h_parse_qos(struct ieee80211_txrx_data *rx)
 		u8 *qc = data + ieee80211_get_hdrlen(rx->fc) - QOS_CONTROL_LEN;
 		/* frame has qos control */
 		tid = qc[0] & QOS_CONTROL_TID_MASK;
+		if (qc[0] & IEEE80211_QOS_CONTROL_A_MSDU_PRESENT)
+			rx->flags |= IEEE80211_TXRXD_RX_AMSDU;
+		else
+			rx->flags &= ~IEEE80211_TXRXD_RX_AMSDU;
 	} else {
 		if (unlikely((rx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT)) {
 			/* Separate TID for management frames */
@@ -262,40 +282,59 @@ ieee80211_rx_h_parse_qos(struct ieee80211_txrx_data *rx)
 	/* Set skb->priority to 1d tag if highest order bit of TID is not set.
 	 * For now, set skb->priority to 0 for other cases. */
 	rx->skb->priority = (tid > 7) ? 0 : tid;
+}
+
+static void ieee80211_verify_ip_alignment(struct ieee80211_txrx_data *rx)
+{
+#ifdef CONFIG_MAC80211_DEBUG_PACKET_ALIGNMENT
+	int hdrlen;
 
-	return TXRX_CONTINUE;
+	if (!WLAN_FC_DATA_PRESENT(rx->fc))
+		return;
+
+	/*
+	 * Drivers are required to align the payload data in a way that
+	 * guarantees that the contained IP header is aligned to a four-
+	 * byte boundary. In the case of regular frames, this simply means
+	 * aligning the payload to a four-byte boundary (because either
+	 * the IP header is directly contained, or IV/RFC1042 headers that
+	 * have a length divisible by four are in front of it.
+	 *
+	 * With A-MSDU frames, however, the payload data address must
+	 * yield two modulo four because there are 14-byte 802.3 headers
+	 * within the A-MSDU frames that push the IP header further back
+	 * to a multiple of four again. Thankfully, the specs were sane
+	 * enough this time around to require padding each A-MSDU subframe
+	 * to a length that is a multiple of four.
+	 *
+	 * Padding like atheros hardware adds which is inbetween the 802.11
+	 * header and the payload is not supported, the driver is required
+	 * to move the 802.11 header further back in that case.
+	 */
+	hdrlen = ieee80211_get_hdrlen(rx->fc);
+	if (rx->flags & IEEE80211_TXRXD_RX_AMSDU)
+		hdrlen += ETH_HLEN;
+	WARN_ON_ONCE(((unsigned long)(rx->skb->data + hdrlen)) & 3);
+#endif
 }
 
-static ieee80211_txrx_result
-ieee80211_rx_h_load_stats(struct ieee80211_txrx_data *rx)
+
+static u32 ieee80211_rx_load_stats(struct ieee80211_local *local,
+				   struct sk_buff *skb,
+				   struct ieee80211_rx_status *status,
+				   struct ieee80211_rate *rate)
 {
-	struct ieee80211_local *local = rx->local;
-	struct sk_buff *skb = rx->skb;
 	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
 	u32 load = 0, hdrtime;
-	struct ieee80211_rate *rate;
-	struct ieee80211_hw_mode *mode = local->hw.conf.mode;
-	int i;
 
 	/* Estimate total channel use caused by this frame */
 
-	if (unlikely(mode->num_rates < 0))
-		return TXRX_CONTINUE;
-
-	rate = &mode->rates[0];
-	for (i = 0; i < mode->num_rates; i++) {
-		if (mode->rates[i].val == rx->u.rx.status->rate) {
-			rate = &mode->rates[i];
-			break;
-		}
-	}
-
 	/* 1 bit at 1 Mbit/s takes 1 usec; in channel_use values,
 	 * 1 usec = 1/8 * (1080 / 10) = 13.5 */
 
-	if (mode->mode == MODE_IEEE80211A ||
-	    (mode->mode == MODE_IEEE80211G &&
-	     rate->flags & IEEE80211_RATE_ERP))
+	if (status->band == IEEE80211_BAND_5GHZ ||
+	    (status->band == IEEE80211_BAND_5GHZ &&
+	     rate->flags & IEEE80211_RATE_ERP_G))
 		hdrtime = CHAN_UTIL_HDR_SHORT;
 	else
 		hdrtime = CHAN_UTIL_HDR_LONG;
@@ -304,55 +343,53 @@ ieee80211_rx_h_load_stats(struct ieee80211_txrx_data *rx)
 	if (!is_multicast_ether_addr(hdr->addr1))
 		load += hdrtime;
 
-	load += skb->len * rate->rate_inv;
+	/* TODO: optimise again */
+	load += skb->len * CHAN_UTIL_RATE_LCM / rate->bitrate;
 
 	/* Divide channel_use by 8 to avoid wrapping around the counter */
 	load >>= CHAN_UTIL_SHIFT;
-	local->channel_use_raw += load;
-	rx->u.rx.load = load;
 
-	return TXRX_CONTINUE;
+	return load;
 }
 
-ieee80211_rx_handler ieee80211_rx_pre_handlers[] =
-{
-	ieee80211_rx_h_parse_qos,
-	ieee80211_rx_h_load_stats,
-	NULL
-};
-
 /* rx handlers */
 
-static ieee80211_txrx_result
+static ieee80211_rx_result
 ieee80211_rx_h_if_stats(struct ieee80211_txrx_data *rx)
 {
 	if (rx->sta)
 		rx->sta->channel_use_raw += rx->u.rx.load;
 	rx->sdata->channel_use_raw += rx->u.rx.load;
-	return TXRX_CONTINUE;
+	return RX_CONTINUE;
 }
 
-static ieee80211_txrx_result
+static ieee80211_rx_result
 ieee80211_rx_h_passive_scan(struct ieee80211_txrx_data *rx)
 {
 	struct ieee80211_local *local = rx->local;
 	struct sk_buff *skb = rx->skb;
 
-	if (unlikely(local->sta_scanning != 0)) {
-		ieee80211_sta_rx_scan(rx->dev, skb, rx->u.rx.status);
-		return TXRX_QUEUED;
+	if (unlikely(local->sta_hw_scanning))
+		return ieee80211_sta_rx_scan(rx->dev, skb, rx->u.rx.status);
+
+	if (unlikely(local->sta_sw_scanning)) {
+		/* drop all the other packets during a software scan anyway */
+		if (ieee80211_sta_rx_scan(rx->dev, skb, rx->u.rx.status)
+		    != RX_QUEUED)
+			dev_kfree_skb(skb);
+		return RX_QUEUED;
 	}
 
 	if (unlikely(rx->flags & IEEE80211_TXRXD_RXIN_SCAN)) {
 		/* scanning finished during invoking of handlers */
 		I802_DEBUG_INC(local->rx_handlers_drop_passive_scan);
-		return TXRX_DROP;
+		return RX_DROP_UNUSABLE;
 	}
 
-	return TXRX_CONTINUE;
+	return RX_CONTINUE;
 }
 
-static ieee80211_txrx_result
+static ieee80211_rx_result
 ieee80211_rx_h_check(struct ieee80211_txrx_data *rx)
 {
 	struct ieee80211_hdr *hdr;
@@ -367,28 +404,16 @@ ieee80211_rx_h_check(struct ieee80211_txrx_data *rx)
 				rx->local->dot11FrameDuplicateCount++;
 				rx->sta->num_duplicates++;
 			}
-			return TXRX_DROP;
+			return RX_DROP_MONITOR;
 		} else
 			rx->sta->last_seq_ctrl[rx->u.rx.queue] = hdr->seq_ctrl;
 	}
 
 	if (unlikely(rx->skb->len < 16)) {
 		I802_DEBUG_INC(rx->local->rx_handlers_drop_short);
-		return TXRX_DROP;
+		return RX_DROP_MONITOR;
 	}
 
-	if (!(rx->flags & IEEE80211_TXRXD_RXRA_MATCH))
-		rx->skb->pkt_type = PACKET_OTHERHOST;
-	else if (compare_ether_addr(rx->dev->dev_addr, hdr->addr1) == 0)
-		rx->skb->pkt_type = PACKET_HOST;
-	else if (is_multicast_ether_addr(hdr->addr1)) {
-		if (is_broadcast_ether_addr(hdr->addr1))
-			rx->skb->pkt_type = PACKET_BROADCAST;
-		else
-			rx->skb->pkt_type = PACKET_MULTICAST;
-	} else
-		rx->skb->pkt_type = PACKET_OTHERHOST;
-
 	/* Drop disallowed frame classes based on STA auth/assoc state;
 	 * IEEE 802.11, Chap 5.5.
 	 *
@@ -400,7 +425,7 @@ ieee80211_rx_h_check(struct ieee80211_txrx_data *rx)
 	if (unlikely(((rx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA ||
 		      ((rx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_CTL &&
 		       (rx->fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_PSPOLL)) &&
-		     rx->sdata->type != IEEE80211_IF_TYPE_IBSS &&
+		     rx->sdata->vif.type != IEEE80211_IF_TYPE_IBSS &&
 		     (!rx->sta || !(rx->sta->flags & WLAN_STA_ASSOC)))) {
 		if ((!(rx->fc & IEEE80211_FCTL_FROMDS) &&
 		     !(rx->fc & IEEE80211_FCTL_TODS) &&
@@ -408,23 +433,23 @@ ieee80211_rx_h_check(struct ieee80211_txrx_data *rx)
 		    || !(rx->flags & IEEE80211_TXRXD_RXRA_MATCH)) {
 			/* Drop IBSS frames and frames for other hosts
 			 * silently. */
-			return TXRX_DROP;
+			return RX_DROP_MONITOR;
 		}
 
-		return TXRX_DROP;
+		return RX_DROP_MONITOR;
 	}
 
-	return TXRX_CONTINUE;
+	return RX_CONTINUE;
 }
 
 
-static ieee80211_txrx_result
+static ieee80211_rx_result
 ieee80211_rx_h_decrypt(struct ieee80211_txrx_data *rx)
 {
 	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) rx->skb->data;
 	int keyidx;
 	int hdrlen;
-	ieee80211_txrx_result result = TXRX_DROP;
+	ieee80211_rx_result result = RX_DROP_UNUSABLE;
 	struct ieee80211_key *stakey = NULL;
 
 	/*
@@ -454,14 +479,14 @@ ieee80211_rx_h_decrypt(struct ieee80211_txrx_data *rx)
 	 */
 
 	if (!(rx->fc & IEEE80211_FCTL_PROTECTED))
-		return TXRX_CONTINUE;
+		return RX_CONTINUE;
 
 	/*
 	 * No point in finding a key and decrypting if the frame is neither
 	 * addressed to us nor a multicast frame.
 	 */
 	if (!(rx->flags & IEEE80211_TXRXD_RXRA_MATCH))
-		return TXRX_CONTINUE;
+		return RX_CONTINUE;
 
 	if (rx->sta)
 		stakey = rcu_dereference(rx->sta->key);
@@ -480,12 +505,12 @@ ieee80211_rx_h_decrypt(struct ieee80211_txrx_data *rx)
 		 */
 		if ((rx->u.rx.status->flag & RX_FLAG_DECRYPTED) &&
 		    (rx->u.rx.status->flag & RX_FLAG_IV_STRIPPED))
-			return TXRX_CONTINUE;
+			return RX_CONTINUE;
 
 		hdrlen = ieee80211_get_hdrlen(rx->fc);
 
 		if (rx->skb->len < 8 + hdrlen)
-			return TXRX_DROP; /* TODO: count this? */
+			return RX_DROP_UNUSABLE; /* TODO: count this? */
 
 		/*
 		 * no need to call ieee80211_wep_get_keyidx,
@@ -509,10 +534,12 @@ ieee80211_rx_h_decrypt(struct ieee80211_txrx_data *rx)
 		rx->key->tx_rx_count++;
 		/* TODO: add threshold stuff again */
 	} else {
+#ifdef CONFIG_MAC80211_DEBUG
 		if (net_ratelimit())
 			printk(KERN_DEBUG "%s: RX protected frame,"
 			       " but have no key\n", rx->dev->name);
-		return TXRX_DROP;
+#endif /* CONFIG_MAC80211_DEBUG */
+		return RX_DROP_MONITOR;
 	}
 
 	/* Check for weak IVs if possible */
@@ -544,6 +571,8 @@ ieee80211_rx_h_decrypt(struct ieee80211_txrx_data *rx)
 static void ap_sta_ps_start(struct net_device *dev, struct sta_info *sta)
 {
 	struct ieee80211_sub_if_data *sdata;
+	DECLARE_MAC_BUF(mac);
+
 	sdata = IEEE80211_DEV_TO_SUB_IF(sta->dev);
 
 	if (sdata->bss)
@@ -551,8 +580,8 @@ static void ap_sta_ps_start(struct net_device *dev, struct sta_info *sta)
 	sta->flags |= WLAN_STA_PS;
 	sta->pspoll = 0;
 #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
-	printk(KERN_DEBUG "%s: STA " MAC_FMT " aid %d enters power "
-	       "save mode\n", dev->name, MAC_ARG(sta->addr), sta->aid);
+	printk(KERN_DEBUG "%s: STA %s aid %d enters power save mode\n",
+	       dev->name, print_mac(mac, sta->addr), sta->aid);
 #endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */
 }
 
@@ -563,6 +592,7 @@ static int ap_sta_ps_end(struct net_device *dev, struct sta_info *sta)
 	int sent = 0;
 	struct ieee80211_sub_if_data *sdata;
 	struct ieee80211_tx_packet_data *pkt_data;
+	DECLARE_MAC_BUF(mac);
 
 	sdata = IEEE80211_DEV_TO_SUB_IF(sta->dev);
 	if (sdata->bss)
@@ -576,8 +606,8 @@ static int ap_sta_ps_end(struct net_device *dev, struct sta_info *sta)
 			bss_tim_clear(local, sdata->bss, sta->aid);
 	}
 #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
-	printk(KERN_DEBUG "%s: STA " MAC_FMT " aid %d exits power "
-	       "save mode\n", dev->name, MAC_ARG(sta->addr), sta->aid);
+	printk(KERN_DEBUG "%s: STA %s aid %d exits power save mode\n",
+	       dev->name, print_mac(mac, sta->addr), sta->aid);
 #endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */
 	/* Send all buffered frames to the station */
 	while ((skb = skb_dequeue(&sta->tx_filtered)) != NULL) {
@@ -591,9 +621,9 @@ static int ap_sta_ps_end(struct net_device *dev, struct sta_info *sta)
 		local->total_ps_buffered--;
 		sent++;
 #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
-		printk(KERN_DEBUG "%s: STA " MAC_FMT " aid %d send PS frame "
+		printk(KERN_DEBUG "%s: STA %s aid %d send PS frame "
 		       "since STA not sleeping anymore\n", dev->name,
-		       MAC_ARG(sta->addr), sta->aid);
+		       print_mac(mac, sta->addr), sta->aid);
 #endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */
 		pkt_data->flags |= IEEE80211_TXPD_REQUEUE;
 		dev_queue_xmit(skb);
@@ -602,7 +632,7 @@ static int ap_sta_ps_end(struct net_device *dev, struct sta_info *sta)
 	return sent;
 }
 
-static ieee80211_txrx_result
+static ieee80211_rx_result
 ieee80211_rx_h_sta_process(struct ieee80211_txrx_data *rx)
 {
 	struct sta_info *sta = rx->sta;
@@ -610,18 +640,19 @@ ieee80211_rx_h_sta_process(struct ieee80211_txrx_data *rx)
 	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) rx->skb->data;
 
 	if (!sta)
-		return TXRX_CONTINUE;
+		return RX_CONTINUE;
 
 	/* Update last_rx only for IBSS packets which are for the current
 	 * BSSID to avoid keeping the current IBSS network alive in cases where
 	 * other STAs are using different BSSID. */
-	if (rx->sdata->type == IEEE80211_IF_TYPE_IBSS) {
-		u8 *bssid = ieee80211_get_bssid(hdr, rx->skb->len);
+	if (rx->sdata->vif.type == IEEE80211_IF_TYPE_IBSS) {
+		u8 *bssid = ieee80211_get_bssid(hdr, rx->skb->len,
+						IEEE80211_IF_TYPE_IBSS);
 		if (compare_ether_addr(bssid, rx->sdata->u.sta.bssid) == 0)
 			sta->last_rx = jiffies;
 	} else
 	if (!is_multicast_ether_addr(hdr->addr1) ||
-	    rx->sdata->type == IEEE80211_IF_TYPE_STA) {
+	    rx->sdata->vif.type == IEEE80211_IF_TYPE_STA) {
 		/* Update last_rx only for unicast frames in order to prevent
 		 * the Probe Request frames (the only broadcast frames from a
 		 * STA in infrastructure mode) from keeping a connection alive.
@@ -630,7 +661,7 @@ ieee80211_rx_h_sta_process(struct ieee80211_txrx_data *rx)
 	}
 
 	if (!(rx->flags & IEEE80211_TXRXD_RXRA_MATCH))
-		return TXRX_CONTINUE;
+		return RX_CONTINUE;
 
 	sta->rx_fragments++;
 	sta->rx_bytes += rx->skb->len;
@@ -657,10 +688,10 @@ ieee80211_rx_h_sta_process(struct ieee80211_txrx_data *rx)
 		 * as a dropped packed. */
 		sta->rx_packets++;
 		dev_kfree_skb(rx->skb);
-		return TXRX_QUEUED;
+		return RX_QUEUED;
 	}
 
-	return TXRX_CONTINUE;
+	return RX_CONTINUE;
 } /* ieee80211_rx_h_sta_process */
 
 static inline struct ieee80211_fragment_entry *
@@ -680,13 +711,15 @@ ieee80211_reassemble_add(struct ieee80211_sub_if_data *sdata,
 #ifdef CONFIG_MAC80211_DEBUG
 		struct ieee80211_hdr *hdr =
 			(struct ieee80211_hdr *) entry->skb_list.next->data;
+		DECLARE_MAC_BUF(mac);
+		DECLARE_MAC_BUF(mac2);
 		printk(KERN_DEBUG "%s: RX reassembly removed oldest "
 		       "fragment entry (idx=%d age=%lu seq=%d last_frag=%d "
-		       "addr1=" MAC_FMT " addr2=" MAC_FMT "\n",
+		       "addr1=%s addr2=%s\n",
 		       sdata->dev->name, idx,
 		       jiffies - entry->first_frag_time, entry->seq,
-		       entry->last_frag, MAC_ARG(hdr->addr1),
-		       MAC_ARG(hdr->addr2));
+		       entry->last_frag, print_mac(mac, hdr->addr1),
+		       print_mac(mac2, hdr->addr2));
 #endif /* CONFIG_MAC80211_DEBUG */
 		__skb_queue_purge(&entry->skb_list);
 	}
@@ -744,7 +777,7 @@ ieee80211_reassemble_find(struct ieee80211_sub_if_data *sdata,
 	return NULL;
 }
 
-static ieee80211_txrx_result
+static ieee80211_rx_result
 ieee80211_rx_h_defragment(struct ieee80211_txrx_data *rx)
 {
 	struct ieee80211_hdr *hdr;
@@ -752,6 +785,7 @@ ieee80211_rx_h_defragment(struct ieee80211_txrx_data *rx)
 	unsigned int frag, seq;
 	struct ieee80211_fragment_entry *entry;
 	struct sk_buff *skb;
+	DECLARE_MAC_BUF(mac);
 
 	hdr = (struct ieee80211_hdr *) rx->skb->data;
 	sc = le16_to_cpu(hdr->seq_ctrl);
@@ -780,7 +814,7 @@ ieee80211_rx_h_defragment(struct ieee80211_txrx_data *rx)
 			       rx->key->u.ccmp.rx_pn[rx->u.rx.queue],
 			       CCMP_PN_LEN);
 		}
-		return TXRX_QUEUED;
+		return RX_QUEUED;
 	}
 
 	/* This is a fragment for a frame that should already be pending in
@@ -790,7 +824,7 @@ ieee80211_rx_h_defragment(struct ieee80211_txrx_data *rx)
 					  rx->u.rx.queue, hdr);
 	if (!entry) {
 		I802_DEBUG_INC(rx->local->rx_handlers_drop_defrag);
-		return TXRX_DROP;
+		return RX_DROP_MONITOR;
 	}
 
 	/* Verify that MPDUs within one MSDU have sequential PN values.
@@ -799,7 +833,7 @@ ieee80211_rx_h_defragment(struct ieee80211_txrx_data *rx)
 		int i;
 		u8 pn[CCMP_PN_LEN], *rpn;
 		if (!rx->key || rx->key->conf.alg != ALG_CCMP)
-			return TXRX_DROP;
+			return RX_DROP_UNUSABLE;
 		memcpy(pn, entry->last_pn, CCMP_PN_LEN);
 		for (i = CCMP_PN_LEN - 1; i >= 0; i--) {
 			pn[i]++;
@@ -810,14 +844,14 @@ ieee80211_rx_h_defragment(struct ieee80211_txrx_data *rx)
 		if (memcmp(pn, rpn, CCMP_PN_LEN) != 0) {
 			if (net_ratelimit())
 				printk(KERN_DEBUG "%s: defrag: CCMP PN not "
-				       "sequential A2=" MAC_FMT
+				       "sequential A2=%s"
 				       " PN=%02x%02x%02x%02x%02x%02x "
 				       "(expected %02x%02x%02x%02x%02x%02x)\n",
-				       rx->dev->name, MAC_ARG(hdr->addr2),
+				       rx->dev->name, print_mac(mac, hdr->addr2),
 				       rpn[0], rpn[1], rpn[2], rpn[3], rpn[4],
 				       rpn[5], pn[0], pn[1], pn[2], pn[3],
 				       pn[4], pn[5]);
-			return TXRX_DROP;
+			return RX_DROP_UNUSABLE;
 		}
 		memcpy(entry->last_pn, pn, CCMP_PN_LEN);
 	}
@@ -828,7 +862,7 @@ ieee80211_rx_h_defragment(struct ieee80211_txrx_data *rx)
 	entry->extra_len += rx->skb->len;
 	if (rx->fc & IEEE80211_FCTL_MOREFRAGS) {
 		rx->skb = NULL;
-		return TXRX_QUEUED;
+		return RX_QUEUED;
 	}
 
 	rx->skb = __skb_dequeue(&entry->skb_list);
@@ -838,7 +872,7 @@ ieee80211_rx_h_defragment(struct ieee80211_txrx_data *rx)
 					      GFP_ATOMIC))) {
 			I802_DEBUG_INC(rx->local->rx_handlers_drop_defrag);
 			__skb_queue_purge(&entry->skb_list);
-			return TXRX_DROP;
+			return RX_DROP_UNUSABLE;
 		}
 	}
 	while ((skb = __skb_dequeue(&entry->skb_list))) {
@@ -856,20 +890,26 @@ ieee80211_rx_h_defragment(struct ieee80211_txrx_data *rx)
 		rx->local->dot11MulticastReceivedFrameCount++;
 	else
 		ieee80211_led_rx(rx->local);
-	return TXRX_CONTINUE;
+	return RX_CONTINUE;
 }
 
-static ieee80211_txrx_result
+static ieee80211_rx_result
 ieee80211_rx_h_ps_poll(struct ieee80211_txrx_data *rx)
 {
+	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(rx->dev);
 	struct sk_buff *skb;
 	int no_pending_pkts;
+	DECLARE_MAC_BUF(mac);
 
 	if (likely(!rx->sta ||
 		   (rx->fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_CTL ||
 		   (rx->fc & IEEE80211_FCTL_STYPE) != IEEE80211_STYPE_PSPOLL ||
 		   !(rx->flags & IEEE80211_TXRXD_RXRA_MATCH)))
-		return TXRX_CONTINUE;
+		return RX_CONTINUE;
+
+	if ((sdata->vif.type != IEEE80211_IF_TYPE_AP) &&
+	    (sdata->vif.type != IEEE80211_IF_TYPE_VLAN))
+		return RX_DROP_UNUSABLE;
 
 	skb = skb_dequeue(&rx->sta->tx_filtered);
 	if (!skb) {
@@ -889,9 +929,8 @@ ieee80211_rx_h_ps_poll(struct ieee80211_txrx_data *rx)
 		rx->sta->pspoll = 1;
 
 #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
-		printk(KERN_DEBUG "STA " MAC_FMT " aid %d: PS Poll (entries "
-		       "after %d)\n",
-		       MAC_ARG(rx->sta->addr), rx->sta->aid,
+		printk(KERN_DEBUG "STA %s aid %d: PS Poll (entries after %d)\n",
+		       print_mac(mac, rx->sta->addr), rx->sta->aid,
 		       skb_queue_len(&rx->sta->ps_tx_buf));
 #endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */
 
@@ -914,21 +953,21 @@ ieee80211_rx_h_ps_poll(struct ieee80211_txrx_data *rx)
 		}
 #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
 	} else if (!rx->u.rx.sent_ps_buffered) {
-		printk(KERN_DEBUG "%s: STA " MAC_FMT " sent PS Poll even "
+		printk(KERN_DEBUG "%s: STA %s sent PS Poll even "
 		       "though there is no buffered frames for it\n",
-		       rx->dev->name, MAC_ARG(rx->sta->addr));
+		       rx->dev->name, print_mac(mac, rx->sta->addr));
 #endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */
 
 	}
 
-	/* Free PS Poll skb here instead of returning TXRX_DROP that would
+	/* Free PS Poll skb here instead of returning RX_DROP that would
 	 * count as an dropped frame. */
 	dev_kfree_skb(rx->skb);
 
-	return TXRX_QUEUED;
+	return RX_QUEUED;
 }
 
-static ieee80211_txrx_result
+static ieee80211_rx_result
 ieee80211_rx_h_remove_qos_control(struct ieee80211_txrx_data *rx)
 {
 	u16 fc = rx->fc;
@@ -936,7 +975,7 @@ ieee80211_rx_h_remove_qos_control(struct ieee80211_txrx_data *rx)
 	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) data;
 
 	if (!WLAN_FC_IS_QOS_DATA(fc))
-		return TXRX_CONTINUE;
+		return RX_CONTINUE;
 
 	/* remove the qos control field, update frame type and meta-data */
 	memmove(data + 2, data, ieee80211_get_hdrlen(fc) - 2);
@@ -945,78 +984,67 @@ ieee80211_rx_h_remove_qos_control(struct ieee80211_txrx_data *rx)
 	rx->fc = fc &= ~IEEE80211_STYPE_QOS_DATA;
 	hdr->frame_control = cpu_to_le16(fc);
 
-	return TXRX_CONTINUE;
+	return RX_CONTINUE;
 }
 
-static ieee80211_txrx_result
-ieee80211_rx_h_802_1x_pae(struct ieee80211_txrx_data *rx)
+static int
+ieee80211_802_1x_port_control(struct ieee80211_txrx_data *rx)
 {
-	if (rx->sdata->eapol && ieee80211_is_eapol(rx->skb) &&
-	    rx->sdata->type != IEEE80211_IF_TYPE_STA &&
-	    (rx->flags & IEEE80211_TXRXD_RXRA_MATCH))
-		return TXRX_CONTINUE;
-
-	if (unlikely(rx->sdata->ieee802_1x &&
-		     (rx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA &&
-		     (rx->fc & IEEE80211_FCTL_STYPE) != IEEE80211_STYPE_NULLFUNC &&
-		     (!rx->sta || !(rx->sta->flags & WLAN_STA_AUTHORIZED)) &&
-		     !ieee80211_is_eapol(rx->skb))) {
+	if (unlikely(!rx->sta || !(rx->sta->flags & WLAN_STA_AUTHORIZED))) {
 #ifdef CONFIG_MAC80211_DEBUG
-		struct ieee80211_hdr *hdr =
-			(struct ieee80211_hdr *) rx->skb->data;
-		printk(KERN_DEBUG "%s: dropped frame from " MAC_FMT
-		       " (unauthorized port)\n", rx->dev->name,
-		       MAC_ARG(hdr->addr2));
+		if (net_ratelimit())
+			printk(KERN_DEBUG "%s: dropped frame "
+			       "(unauthorized port)\n", rx->dev->name);
 #endif /* CONFIG_MAC80211_DEBUG */
-		return TXRX_DROP;
+		return -EACCES;
 	}
 
-	return TXRX_CONTINUE;
+	return 0;
 }
 
-static ieee80211_txrx_result
-ieee80211_rx_h_drop_unencrypted(struct ieee80211_txrx_data *rx)
+static int
+ieee80211_drop_unencrypted(struct ieee80211_txrx_data *rx)
 {
 	/*
 	 * Pass through unencrypted frames if the hardware has
 	 * decrypted them already.
 	 */
 	if (rx->u.rx.status->flag & RX_FLAG_DECRYPTED)
-		return TXRX_CONTINUE;
+		return 0;
 
 	/* Drop unencrypted frames if key is set. */
 	if (unlikely(!(rx->fc & IEEE80211_FCTL_PROTECTED) &&
 		     (rx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA &&
 		     (rx->fc & IEEE80211_FCTL_STYPE) != IEEE80211_STYPE_NULLFUNC &&
-		     rx->sdata->drop_unencrypted &&
-		     (rx->sdata->eapol == 0 || !ieee80211_is_eapol(rx->skb)))) {
+		     (rx->key || rx->sdata->drop_unencrypted))) {
 		if (net_ratelimit())
 			printk(KERN_DEBUG "%s: RX non-WEP frame, but expected "
 			       "encryption\n", rx->dev->name);
-		return TXRX_DROP;
+		return -EACCES;
 	}
-	return TXRX_CONTINUE;
+	return 0;
 }
 
-static ieee80211_txrx_result
-ieee80211_rx_h_data(struct ieee80211_txrx_data *rx)
+static int
+ieee80211_data_to_8023(struct ieee80211_txrx_data *rx)
 {
 	struct net_device *dev = rx->dev;
-	struct ieee80211_local *local = rx->local;
 	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) rx->skb->data;
 	u16 fc, hdrlen, ethertype;
 	u8 *payload;
 	u8 dst[ETH_ALEN];
 	u8 src[ETH_ALEN];
-	struct sk_buff *skb = rx->skb, *skb2;
+	struct sk_buff *skb = rx->skb;
 	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+	DECLARE_MAC_BUF(mac);
+	DECLARE_MAC_BUF(mac2);
+	DECLARE_MAC_BUF(mac3);
+	DECLARE_MAC_BUF(mac4);
 
 	fc = rx->fc;
-	if (unlikely((fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA))
-		return TXRX_CONTINUE;
 
 	if (unlikely(!WLAN_FC_DATA_PRESENT(fc)))
-		return TXRX_DROP;
+		return -1;
 
 	hdrlen = ieee80211_get_hdrlen(fc);
 
@@ -1036,18 +1064,16 @@ ieee80211_rx_h_data(struct ieee80211_txrx_data *rx)
 		memcpy(dst, hdr->addr3, ETH_ALEN);
 		memcpy(src, hdr->addr2, ETH_ALEN);
 
-		if (unlikely(sdata->type != IEEE80211_IF_TYPE_AP &&
-			     sdata->type != IEEE80211_IF_TYPE_VLAN)) {
+		if (unlikely(sdata->vif.type != IEEE80211_IF_TYPE_AP &&
+			     sdata->vif.type != IEEE80211_IF_TYPE_VLAN)) {
 			if (net_ratelimit())
 				printk(KERN_DEBUG "%s: dropped ToDS frame "
-				       "(BSSID=" MAC_FMT
-				       " SA=" MAC_FMT
-				       " DA=" MAC_FMT ")\n",
+				       "(BSSID=%s SA=%s DA=%s)\n",
 				       dev->name,
-				       MAC_ARG(hdr->addr1),
-				       MAC_ARG(hdr->addr2),
-				       MAC_ARG(hdr->addr3));
-			return TXRX_DROP;
+				       print_mac(mac, hdr->addr1),
+				       print_mac(mac2, hdr->addr2),
+				       print_mac(mac3, hdr->addr3));
+			return -1;
 		}
 		break;
 	case (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS):
@@ -1055,18 +1081,16 @@ ieee80211_rx_h_data(struct ieee80211_txrx_data *rx)
 		memcpy(dst, hdr->addr3, ETH_ALEN);
 		memcpy(src, hdr->addr4, ETH_ALEN);
 
-		if (unlikely(sdata->type != IEEE80211_IF_TYPE_WDS)) {
+		if (unlikely(sdata->vif.type != IEEE80211_IF_TYPE_WDS)) {
 			if (net_ratelimit())
 				printk(KERN_DEBUG "%s: dropped FromDS&ToDS "
-				       "frame (RA=" MAC_FMT
-				       " TA=" MAC_FMT " DA=" MAC_FMT
-				       " SA=" MAC_FMT ")\n",
+				       "frame (RA=%s TA=%s DA=%s SA=%s)\n",
 				       rx->dev->name,
-				       MAC_ARG(hdr->addr1),
-				       MAC_ARG(hdr->addr2),
-				       MAC_ARG(hdr->addr3),
-				       MAC_ARG(hdr->addr4));
-			return TXRX_DROP;
+				       print_mac(mac, hdr->addr1),
+				       print_mac(mac2, hdr->addr2),
+				       print_mac(mac3, hdr->addr3),
+				       print_mac(mac4, hdr->addr4));
+			return -1;
 		}
 		break;
 	case IEEE80211_FCTL_FROMDS:
@@ -1074,40 +1098,39 @@ ieee80211_rx_h_data(struct ieee80211_txrx_data *rx)
 		memcpy(dst, hdr->addr1, ETH_ALEN);
 		memcpy(src, hdr->addr3, ETH_ALEN);
 
-		if (sdata->type != IEEE80211_IF_TYPE_STA ||
+		if (sdata->vif.type != IEEE80211_IF_TYPE_STA ||
 		    (is_multicast_ether_addr(dst) &&
 		     !compare_ether_addr(src, dev->dev_addr)))
-			return TXRX_DROP;
+			return -1;
 		break;
 	case 0:
 		/* DA SA BSSID */
 		memcpy(dst, hdr->addr1, ETH_ALEN);
 		memcpy(src, hdr->addr2, ETH_ALEN);
 
-		if (sdata->type != IEEE80211_IF_TYPE_IBSS) {
+		if (sdata->vif.type != IEEE80211_IF_TYPE_IBSS) {
 			if (net_ratelimit()) {
-				printk(KERN_DEBUG "%s: dropped IBSS frame (DA="
-				       MAC_FMT " SA=" MAC_FMT " BSSID=" MAC_FMT
-				       ")\n",
-				       dev->name, MAC_ARG(hdr->addr1),
-				       MAC_ARG(hdr->addr2),
-				       MAC_ARG(hdr->addr3));
+				printk(KERN_DEBUG "%s: dropped IBSS frame "
+				       "(DA=%s SA=%s BSSID=%s)\n",
+				       dev->name,
+				       print_mac(mac, hdr->addr1),
+				       print_mac(mac2, hdr->addr2),
+				       print_mac(mac3, hdr->addr3));
 			}
-			return TXRX_DROP;
+			return -1;
 		}
 		break;
 	}
 
-	payload = skb->data + hdrlen;
-
 	if (unlikely(skb->len - hdrlen < 8)) {
 		if (net_ratelimit()) {
 			printk(KERN_DEBUG "%s: RX too short data frame "
 			       "payload\n", dev->name);
 		}
-		return TXRX_DROP;
+		return -1;
 	}
 
+	payload = skb->data + hdrlen;
 	ethertype = (payload[6] << 8) | payload[7];
 
 	if (likely((compare_ether_addr(payload, rfc1042_header) == 0 &&
@@ -1121,6 +1144,7 @@ ieee80211_rx_h_data(struct ieee80211_txrx_data *rx)
 	} else {
 		struct ethhdr *ehdr;
 		__be16 len;
+
 		skb_pull(skb, hdrlen);
 		len = htons(skb->len);
 		ehdr = (struct ethhdr *) skb_push(skb, sizeof(struct ethhdr));
@@ -1128,36 +1152,72 @@ ieee80211_rx_h_data(struct ieee80211_txrx_data *rx)
 		memcpy(ehdr->h_source, src, ETH_ALEN);
 		ehdr->h_proto = len;
 	}
-	skb->dev = dev;
+	return 0;
+}
 
-	skb2 = NULL;
+/*
+ * requires that rx->skb is a frame with ethernet header
+ */
+static bool ieee80211_frame_allowed(struct ieee80211_txrx_data *rx)
+{
+	static const u8 pae_group_addr[ETH_ALEN]
+		= { 0x01, 0x80, 0xC2, 0x00, 0x00, 0x03 };
+	struct ethhdr *ehdr = (struct ethhdr *) rx->skb->data;
 
-	dev->stats.rx_packets++;
-	dev->stats.rx_bytes += skb->len;
+	/*
+	 * Allow EAPOL frames to us/the PAE group address regardless
+	 * of whether the frame was encrypted or not.
+	 */
+	if (ehdr->h_proto == htons(ETH_P_PAE) &&
+	    (compare_ether_addr(ehdr->h_dest, rx->dev->dev_addr) == 0 ||
+	     compare_ether_addr(ehdr->h_dest, pae_group_addr) == 0))
+		return true;
+
+	if (ieee80211_802_1x_port_control(rx) ||
+	    ieee80211_drop_unencrypted(rx))
+		return false;
+
+	return true;
+}
+
+/*
+ * requires that rx->skb is a frame with ethernet header
+ */
+static void
+ieee80211_deliver_skb(struct ieee80211_txrx_data *rx)
+{
+	struct net_device *dev = rx->dev;
+	struct ieee80211_local *local = rx->local;
+	struct sk_buff *skb, *xmit_skb;
+	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+	struct ethhdr *ehdr = (struct ethhdr *) rx->skb->data;
+	struct sta_info *dsta;
 
-	if (local->bridge_packets && (sdata->type == IEEE80211_IF_TYPE_AP
-	    || sdata->type == IEEE80211_IF_TYPE_VLAN) &&
+	skb = rx->skb;
+	xmit_skb = NULL;
+
+	if (local->bridge_packets && (sdata->vif.type == IEEE80211_IF_TYPE_AP ||
+				      sdata->vif.type == IEEE80211_IF_TYPE_VLAN) &&
 	    (rx->flags & IEEE80211_TXRXD_RXRA_MATCH)) {
-		if (is_multicast_ether_addr(skb->data)) {
-			/* send multicast frames both to higher layers in
-			 * local net stack and back to the wireless media */
-			skb2 = skb_copy(skb, GFP_ATOMIC);
-			if (!skb2 && net_ratelimit())
+		if (is_multicast_ether_addr(ehdr->h_dest)) {
+			/*
+			 * send multicast frames both to higher layers in
+			 * local net stack and back to the wireless medium
+			 */
+			xmit_skb = skb_copy(skb, GFP_ATOMIC);
+			if (!xmit_skb && net_ratelimit())
 				printk(KERN_DEBUG "%s: failed to clone "
 				       "multicast frame\n", dev->name);
 		} else {
-			struct sta_info *dsta;
 			dsta = sta_info_get(local, skb->data);
-			if (dsta && !dsta->dev) {
-				if (net_ratelimit())
-					printk(KERN_DEBUG "Station with null "
-					       "dev structure!\n");
-			} else if (dsta && dsta->dev == dev) {
-				/* Destination station is associated to this
-				 * AP, so send the frame directly to it and
-				 * do not pass the frame to local net stack.
+			if (dsta && dsta->dev == dev) {
+				/*
+				 * The destination station is associated to
+				 * this AP (in this VLAN), so send the frame
+				 * directly to it and do not pass it to local
+				 * net stack.
 				 */
-				skb2 = skb;
+				xmit_skb = skb;
 				skb = NULL;
 			}
 			if (dsta)
@@ -1172,84 +1232,232 @@ ieee80211_rx_h_data(struct ieee80211_txrx_data *rx)
 		netif_rx(skb);
 	}
 
-	if (skb2) {
+	if (xmit_skb) {
 		/* send to wireless media */
-		skb2->protocol = __constant_htons(ETH_P_802_3);
-		skb_set_network_header(skb2, 0);
-		skb_set_mac_header(skb2, 0);
-		dev_queue_xmit(skb2);
+		xmit_skb->protocol = __constant_htons(ETH_P_802_3);
+		skb_reset_network_header(xmit_skb);
+		skb_reset_mac_header(xmit_skb);
+		dev_queue_xmit(xmit_skb);
 	}
-
-	return TXRX_QUEUED;
 }
 
-static ieee80211_txrx_result
-ieee80211_rx_h_mgmt(struct ieee80211_txrx_data *rx)
+static ieee80211_rx_result
+ieee80211_rx_h_amsdu(struct ieee80211_txrx_data *rx)
 {
-	struct ieee80211_sub_if_data *sdata;
+	struct net_device *dev = rx->dev;
+	struct ieee80211_local *local = rx->local;
+	u16 fc, ethertype;
+	u8 *payload;
+	struct sk_buff *skb = rx->skb, *frame = NULL;
+	const struct ethhdr *eth;
+	int remaining, err;
+	u8 dst[ETH_ALEN];
+	u8 src[ETH_ALEN];
+	DECLARE_MAC_BUF(mac);
 
-	if (!(rx->flags & IEEE80211_TXRXD_RXRA_MATCH))
-		return TXRX_DROP;
+	fc = rx->fc;
+	if (unlikely((fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA))
+		return RX_CONTINUE;
 
-	sdata = IEEE80211_DEV_TO_SUB_IF(rx->dev);
-	if ((sdata->type == IEEE80211_IF_TYPE_STA ||
-	     sdata->type == IEEE80211_IF_TYPE_IBSS) &&
-	    !(sdata->flags & IEEE80211_SDATA_USERSPACE_MLME))
-		ieee80211_sta_rx_mgmt(rx->dev, rx->skb, rx->u.rx.status);
-	else
-		return TXRX_DROP;
+	if (unlikely(!WLAN_FC_DATA_PRESENT(fc)))
+		return RX_DROP_MONITOR;
 
-	return TXRX_QUEUED;
+	if (!(rx->flags & IEEE80211_TXRXD_RX_AMSDU))
+		return RX_CONTINUE;
+
+	err = ieee80211_data_to_8023(rx);
+	if (unlikely(err))
+		return RX_DROP_UNUSABLE;
+
+	skb->dev = dev;
+
+	dev->stats.rx_packets++;
+	dev->stats.rx_bytes += skb->len;
+
+	/* skip the wrapping header */
+	eth = (struct ethhdr *) skb_pull(skb, sizeof(struct ethhdr));
+	if (!eth)
+		return RX_DROP_UNUSABLE;
+
+	while (skb != frame) {
+		u8 padding;
+		__be16 len = eth->h_proto;
+		unsigned int subframe_len = sizeof(struct ethhdr) + ntohs(len);
+
+		remaining = skb->len;
+		memcpy(dst, eth->h_dest, ETH_ALEN);
+		memcpy(src, eth->h_source, ETH_ALEN);
+
+		padding = ((4 - subframe_len) & 0x3);
+		/* the last MSDU has no padding */
+		if (subframe_len > remaining) {
+			printk(KERN_DEBUG "%s: wrong buffer size", dev->name);
+			return RX_DROP_UNUSABLE;
+		}
+
+		skb_pull(skb, sizeof(struct ethhdr));
+		/* if last subframe reuse skb */
+		if (remaining <= subframe_len + padding)
+			frame = skb;
+		else {
+			frame = dev_alloc_skb(local->hw.extra_tx_headroom +
+					      subframe_len);
+
+			if (frame == NULL)
+				return RX_DROP_UNUSABLE;
+
+			skb_reserve(frame, local->hw.extra_tx_headroom +
+				    sizeof(struct ethhdr));
+			memcpy(skb_put(frame, ntohs(len)), skb->data,
+				ntohs(len));
+
+			eth = (struct ethhdr *) skb_pull(skb, ntohs(len) +
+							padding);
+			if (!eth) {
+				printk(KERN_DEBUG "%s: wrong buffer size ",
+				       dev->name);
+				dev_kfree_skb(frame);
+				return RX_DROP_UNUSABLE;
+			}
+		}
+
+		skb_reset_network_header(frame);
+		frame->dev = dev;
+		frame->priority = skb->priority;
+		rx->skb = frame;
+
+		payload = frame->data;
+		ethertype = (payload[6] << 8) | payload[7];
+
+		if (likely((compare_ether_addr(payload, rfc1042_header) == 0 &&
+			    ethertype != ETH_P_AARP && ethertype != ETH_P_IPX) ||
+			   compare_ether_addr(payload,
+					      bridge_tunnel_header) == 0)) {
+			/* remove RFC1042 or Bridge-Tunnel
+			 * encapsulation and replace EtherType */
+			skb_pull(frame, 6);
+			memcpy(skb_push(frame, ETH_ALEN), src, ETH_ALEN);
+			memcpy(skb_push(frame, ETH_ALEN), dst, ETH_ALEN);
+		} else {
+			memcpy(skb_push(frame, sizeof(__be16)),
+			       &len, sizeof(__be16));
+			memcpy(skb_push(frame, ETH_ALEN), src, ETH_ALEN);
+			memcpy(skb_push(frame, ETH_ALEN), dst, ETH_ALEN);
+		}
+
+		if (!ieee80211_frame_allowed(rx)) {
+			if (skb == frame) /* last frame */
+				return RX_DROP_UNUSABLE;
+			dev_kfree_skb(frame);
+			continue;
+		}
+
+		ieee80211_deliver_skb(rx);
+	}
+
+	return RX_QUEUED;
 }
 
-static inline ieee80211_txrx_result __ieee80211_invoke_rx_handlers(
-				struct ieee80211_local *local,
-				ieee80211_rx_handler *handlers,
-				struct ieee80211_txrx_data *rx,
-				struct sta_info *sta)
+static ieee80211_rx_result
+ieee80211_rx_h_data(struct ieee80211_txrx_data *rx)
 {
-	ieee80211_rx_handler *handler;
-	ieee80211_txrx_result res = TXRX_DROP;
+	struct net_device *dev = rx->dev;
+	u16 fc;
+	int err;
 
-	for (handler = handlers; *handler != NULL; handler++) {
-		res = (*handler)(rx);
+	fc = rx->fc;
+	if (unlikely((fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA))
+		return RX_CONTINUE;
 
-		switch (res) {
-		case TXRX_CONTINUE:
-			continue;
-		case TXRX_DROP:
-			I802_DEBUG_INC(local->rx_handlers_drop);
-			if (sta)
-				sta->rx_dropped++;
-			break;
-		case TXRX_QUEUED:
-			I802_DEBUG_INC(local->rx_handlers_queued);
-			break;
+	if (unlikely(!WLAN_FC_DATA_PRESENT(fc)))
+		return RX_DROP_MONITOR;
+
+	err = ieee80211_data_to_8023(rx);
+	if (unlikely(err))
+		return RX_DROP_UNUSABLE;
+
+	if (!ieee80211_frame_allowed(rx))
+		return RX_DROP_MONITOR;
+
+	rx->skb->dev = dev;
+
+	dev->stats.rx_packets++;
+	dev->stats.rx_bytes += rx->skb->len;
+
+	ieee80211_deliver_skb(rx);
+
+	return RX_QUEUED;
+}
+
+static ieee80211_rx_result
+ieee80211_rx_h_ctrl(struct ieee80211_txrx_data *rx)
+{
+	struct ieee80211_local *local = rx->local;
+	struct ieee80211_hw *hw = &local->hw;
+	struct sk_buff *skb = rx->skb;
+	struct ieee80211_bar *bar = (struct ieee80211_bar *) skb->data;
+	struct tid_ampdu_rx *tid_agg_rx;
+	u16 start_seq_num;
+	u16 tid;
+
+	if (likely((rx->fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_CTL))
+		return RX_CONTINUE;
+
+	if ((rx->fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_BACK_REQ) {
+		if (!rx->sta)
+			return RX_CONTINUE;
+		tid = le16_to_cpu(bar->control) >> 12;
+		tid_agg_rx = &(rx->sta->ampdu_mlme.tid_rx[tid]);
+		if (tid_agg_rx->state != HT_AGG_STATE_OPERATIONAL)
+			return RX_CONTINUE;
+
+		start_seq_num = le16_to_cpu(bar->start_seq_num) >> 4;
+
+		/* reset session timer */
+		if (tid_agg_rx->timeout) {
+			unsigned long expires =
+				jiffies + (tid_agg_rx->timeout / 1000) * HZ;
+			mod_timer(&tid_agg_rx->session_timer, expires);
 		}
-		break;
+
+		/* manage reordering buffer according to requested */
+		/* sequence number */
+		rcu_read_lock();
+		ieee80211_sta_manage_reorder_buf(hw, tid_agg_rx, NULL,
+						 start_seq_num, 1);
+		rcu_read_unlock();
+		return RX_DROP_UNUSABLE;
 	}
 
-	if (res == TXRX_DROP)
-		dev_kfree_skb(rx->skb);
-	return res;
+	return RX_CONTINUE;
 }
 
-static inline void ieee80211_invoke_rx_handlers(struct ieee80211_local *local,
-						ieee80211_rx_handler *handlers,
-						struct ieee80211_txrx_data *rx,
-						struct sta_info *sta)
+static ieee80211_rx_result
+ieee80211_rx_h_mgmt(struct ieee80211_txrx_data *rx)
 {
-	if (__ieee80211_invoke_rx_handlers(local, handlers, rx, sta) ==
-	    TXRX_CONTINUE)
-		dev_kfree_skb(rx->skb);
+	struct ieee80211_sub_if_data *sdata;
+
+	if (!(rx->flags & IEEE80211_TXRXD_RXRA_MATCH))
+		return RX_DROP_MONITOR;
+
+	sdata = IEEE80211_DEV_TO_SUB_IF(rx->dev);
+	if ((sdata->vif.type == IEEE80211_IF_TYPE_STA ||
+	     sdata->vif.type == IEEE80211_IF_TYPE_IBSS) &&
+	    !(sdata->flags & IEEE80211_SDATA_USERSPACE_MLME))
+		ieee80211_sta_rx_mgmt(rx->dev, rx->skb, rx->u.rx.status);
+	else
+		return RX_DROP_MONITOR;
+
+	return RX_QUEUED;
 }
 
 static void ieee80211_rx_michael_mic_report(struct net_device *dev,
 					    struct ieee80211_hdr *hdr,
-					    struct sta_info *sta,
 					    struct ieee80211_txrx_data *rx)
 {
 	int keyidx, hdrlen;
+	DECLARE_MAC_BUF(mac);
+	DECLARE_MAC_BUF(mac2);
 
 	hdrlen = ieee80211_get_hdrlen_from_skb(rx->skb);
 	if (rx->skb->len >= hdrlen + 4)
@@ -1259,19 +1467,19 @@ static void ieee80211_rx_michael_mic_report(struct net_device *dev,
 
 	if (net_ratelimit())
 		printk(KERN_DEBUG "%s: TKIP hwaccel reported Michael MIC "
-		       "failure from " MAC_FMT " to " MAC_FMT " keyidx=%d\n",
-		       dev->name, MAC_ARG(hdr->addr2), MAC_ARG(hdr->addr1),
-		       keyidx);
+		       "failure from %s to %s keyidx=%d\n",
+		       dev->name, print_mac(mac, hdr->addr2),
+		       print_mac(mac2, hdr->addr1), keyidx);
 
-	if (!sta) {
+	if (!rx->sta) {
 		/*
 		 * Some hardware seem to generate incorrect Michael MIC
 		 * reports; ignore them to avoid triggering countermeasures.
 		 */
 		if (net_ratelimit())
 			printk(KERN_DEBUG "%s: ignored spurious Michael MIC "
-			       "error for unknown address " MAC_FMT "\n",
-			       dev->name, MAC_ARG(hdr->addr2));
+			       "error for unknown address %s\n",
+			       dev->name, print_mac(mac, hdr->addr2));
 		goto ignore;
 	}
 
@@ -1279,11 +1487,11 @@ static void ieee80211_rx_michael_mic_report(struct net_device *dev,
 		if (net_ratelimit())
 			printk(KERN_DEBUG "%s: ignored spurious Michael MIC "
 			       "error for a frame with no PROTECTED flag (src "
-			       MAC_FMT ")\n", dev->name, MAC_ARG(hdr->addr2));
+			       "%s)\n", dev->name, print_mac(mac, hdr->addr2));
 		goto ignore;
 	}
 
-	if (rx->sdata->type == IEEE80211_IF_TYPE_AP && keyidx) {
+	if (rx->sdata->vif.type == IEEE80211_IF_TYPE_AP && keyidx) {
 		/*
 		 * APs with pairwise keys should never receive Michael MIC
 		 * errors for non-zero keyidx because these are reserved for
@@ -1293,8 +1501,8 @@ static void ieee80211_rx_michael_mic_report(struct net_device *dev,
 		if (net_ratelimit())
 			printk(KERN_DEBUG "%s: ignored Michael MIC error for "
 			       "a frame with non-zero keyidx (%d)"
-			       " (src " MAC_FMT ")\n", dev->name, keyidx,
-			       MAC_ARG(hdr->addr2));
+			       " (src %s)\n", dev->name, keyidx,
+			       print_mac(mac, hdr->addr2));
 		goto ignore;
 	}
 
@@ -1304,8 +1512,8 @@ static void ieee80211_rx_michael_mic_report(struct net_device *dev,
 		if (net_ratelimit())
 			printk(KERN_DEBUG "%s: ignored spurious Michael MIC "
 			       "error for a frame that cannot be encrypted "
-			       "(fc=0x%04x) (src " MAC_FMT ")\n",
-			       dev->name, rx->fc, MAC_ARG(hdr->addr2));
+			       "(fc=0x%04x) (src %s)\n",
+			       dev->name, rx->fc, print_mac(mac, hdr->addr2));
 		goto ignore;
 	}
 
@@ -1315,7 +1523,88 @@ static void ieee80211_rx_michael_mic_report(struct net_device *dev,
 	rx->skb = NULL;
 }
 
-ieee80211_rx_handler ieee80211_rx_handlers[] =
+static void ieee80211_rx_cooked_monitor(struct ieee80211_txrx_data *rx)
+{
+	struct ieee80211_sub_if_data *sdata;
+	struct ieee80211_local *local = rx->local;
+	struct ieee80211_rtap_hdr {
+		struct ieee80211_radiotap_header hdr;
+		u8 flags;
+		u8 rate;
+		__le16 chan_freq;
+		__le16 chan_flags;
+	} __attribute__ ((packed)) *rthdr;
+	struct sk_buff *skb = rx->skb, *skb2;
+	struct net_device *prev_dev = NULL;
+	struct ieee80211_rx_status *status = rx->u.rx.status;
+
+	if (rx->flags & IEEE80211_TXRXD_RX_CMNTR_REPORTED)
+		goto out_free_skb;
+
+	if (skb_headroom(skb) < sizeof(*rthdr) &&
+	    pskb_expand_head(skb, sizeof(*rthdr), 0, GFP_ATOMIC))
+		goto out_free_skb;
+
+	rthdr = (void *)skb_push(skb, sizeof(*rthdr));
+	memset(rthdr, 0, sizeof(*rthdr));
+	rthdr->hdr.it_len = cpu_to_le16(sizeof(*rthdr));
+	rthdr->hdr.it_present =
+		cpu_to_le32((1 << IEEE80211_RADIOTAP_FLAGS) |
+			    (1 << IEEE80211_RADIOTAP_RATE) |
+			    (1 << IEEE80211_RADIOTAP_CHANNEL));
+
+	rthdr->rate = rx->u.rx.rate->bitrate / 5;
+	rthdr->chan_freq = cpu_to_le16(status->freq);
+
+	if (status->band == IEEE80211_BAND_5GHZ)
+		rthdr->chan_flags = cpu_to_le16(IEEE80211_CHAN_OFDM |
+						IEEE80211_CHAN_5GHZ);
+	else
+		rthdr->chan_flags = cpu_to_le16(IEEE80211_CHAN_DYN |
+						IEEE80211_CHAN_2GHZ);
+
+	skb_set_mac_header(skb, 0);
+	skb->ip_summed = CHECKSUM_UNNECESSARY;
+	skb->pkt_type = PACKET_OTHERHOST;
+	skb->protocol = htons(ETH_P_802_2);
+
+	list_for_each_entry_rcu(sdata, &local->interfaces, list) {
+		if (!netif_running(sdata->dev))
+			continue;
+
+		if (sdata->vif.type != IEEE80211_IF_TYPE_MNTR ||
+		    !(sdata->u.mntr_flags & MONITOR_FLAG_COOK_FRAMES))
+			continue;
+
+		if (prev_dev) {
+			skb2 = skb_clone(skb, GFP_ATOMIC);
+			if (skb2) {
+				skb2->dev = prev_dev;
+				netif_rx(skb2);
+			}
+		}
+
+		prev_dev = sdata->dev;
+		sdata->dev->stats.rx_packets++;
+		sdata->dev->stats.rx_bytes += skb->len;
+	}
+
+	if (prev_dev) {
+		skb->dev = prev_dev;
+		netif_rx(skb);
+		skb = NULL;
+	} else
+		goto out_free_skb;
+
+	rx->flags |= IEEE80211_TXRXD_RX_CMNTR_REPORTED;
+	return;
+
+ out_free_skb:
+	dev_kfree_skb(skb);
+}
+
+typedef ieee80211_rx_result (*ieee80211_rx_handler)(struct ieee80211_txrx_data *);
+static ieee80211_rx_handler ieee80211_rx_handlers[] =
 {
 	ieee80211_rx_h_if_stats,
 	ieee80211_rx_h_passive_scan,
@@ -1330,13 +1619,54 @@ ieee80211_rx_handler ieee80211_rx_handlers[] =
 	 * are not passed to user space by these functions
 	 */
 	ieee80211_rx_h_remove_qos_control,
-	ieee80211_rx_h_802_1x_pae,
-	ieee80211_rx_h_drop_unencrypted,
+	ieee80211_rx_h_amsdu,
 	ieee80211_rx_h_data,
+	ieee80211_rx_h_ctrl,
 	ieee80211_rx_h_mgmt,
 	NULL
 };
 
+static void ieee80211_invoke_rx_handlers(struct ieee80211_sub_if_data *sdata,
+					 struct ieee80211_txrx_data *rx,
+					 struct sk_buff *skb)
+{
+	ieee80211_rx_handler *handler;
+	ieee80211_rx_result res = RX_DROP_MONITOR;
+
+	rx->skb = skb;
+	rx->sdata = sdata;
+	rx->dev = sdata->dev;
+
+	for (handler = ieee80211_rx_handlers; *handler != NULL; handler++) {
+		res = (*handler)(rx);
+
+		switch (res) {
+		case RX_CONTINUE:
+			continue;
+		case RX_DROP_UNUSABLE:
+		case RX_DROP_MONITOR:
+			I802_DEBUG_INC(sdata->local->rx_handlers_drop);
+			if (rx->sta)
+				rx->sta->rx_dropped++;
+			break;
+		case RX_QUEUED:
+			I802_DEBUG_INC(sdata->local->rx_handlers_queued);
+			break;
+		}
+		break;
+	}
+
+	switch (res) {
+	case RX_CONTINUE:
+	case RX_DROP_MONITOR:
+		ieee80211_rx_cooked_monitor(rx);
+		break;
+	case RX_DROP_UNUSABLE:
+		dev_kfree_skb(rx->skb);
+		break;
+	}
+}
+
 /* main receive path */
 
 static int prepare_for_handlers(struct ieee80211_sub_if_data *sdata,
@@ -1345,7 +1675,7 @@ static int prepare_for_handlers(struct ieee80211_sub_if_data *sdata,
 {
 	int multicast = is_multicast_ether_addr(hdr->addr1);
 
-	switch (sdata->type) {
+	switch (sdata->vif.type) {
 	case IEEE80211_IF_TYPE_STA:
 		if (!bssid)
 			return 0;
@@ -1416,99 +1746,70 @@ static int prepare_for_handlers(struct ieee80211_sub_if_data *sdata,
 }
 
 /*
- * This is the receive path handler. It is called by a low level driver when an
- * 802.11 MPDU is received from the hardware.
+ * This is the actual Rx frames handler. as it blongs to Rx path it must
+ * be called with rcu_read_lock protection.
  */
-void __ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb,
-		    struct ieee80211_rx_status *status)
+static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw,
+					 struct sk_buff *skb,
+					 struct ieee80211_rx_status *status,
+					 u32 load,
+					 struct ieee80211_rate *rate)
 {
 	struct ieee80211_local *local = hw_to_local(hw);
 	struct ieee80211_sub_if_data *sdata;
-	struct sta_info *sta;
 	struct ieee80211_hdr *hdr;
 	struct ieee80211_txrx_data rx;
 	u16 type;
-	int prepres;
+	int prepares;
 	struct ieee80211_sub_if_data *prev = NULL;
 	struct sk_buff *skb_new;
 	u8 *bssid;
 
-	/*
-	 * key references and virtual interfaces are protected using RCU
-	 * and this requires that we are in a read-side RCU section during
-	 * receive processing
-	 */
-	rcu_read_lock();
-
-	/*
-	 * Frames with failed FCS/PLCP checksum are not returned,
-	 * all other frames are returned without radiotap header
-	 * if it was previously present.
-	 * Also, frames with less than 16 bytes are dropped.
-	 */
-	skb = ieee80211_rx_monitor(local, skb, status);
-	if (!skb) {
-		rcu_read_unlock();
-		return;
-	}
-
 	hdr = (struct ieee80211_hdr *) skb->data;
 	memset(&rx, 0, sizeof(rx));
 	rx.skb = skb;
 	rx.local = local;
 
 	rx.u.rx.status = status;
+	rx.u.rx.load = load;
+	rx.u.rx.rate = rate;
 	rx.fc = le16_to_cpu(hdr->frame_control);
 	type = rx.fc & IEEE80211_FCTL_FTYPE;
 
 	if (type == IEEE80211_FTYPE_DATA || type == IEEE80211_FTYPE_MGMT)
 		local->dot11ReceivedFragmentCount++;
 
-	sta = rx.sta = sta_info_get(local, hdr->addr2);
-	if (sta) {
+	rx.sta = sta_info_get(local, hdr->addr2);
+	if (rx.sta) {
 		rx.dev = rx.sta->dev;
 		rx.sdata = IEEE80211_DEV_TO_SUB_IF(rx.dev);
 	}
 
 	if ((status->flag & RX_FLAG_MMIC_ERROR)) {
-		ieee80211_rx_michael_mic_report(local->mdev, hdr, sta, &rx);
+		ieee80211_rx_michael_mic_report(local->mdev, hdr, &rx);
 		goto end;
 	}
 
-	if (unlikely(local->sta_scanning))
+	if (unlikely(local->sta_sw_scanning || local->sta_hw_scanning))
 		rx.flags |= IEEE80211_TXRXD_RXIN_SCAN;
 
-	if (__ieee80211_invoke_rx_handlers(local, local->rx_pre_handlers, &rx,
-					   sta) != TXRX_CONTINUE)
-		goto end;
-	skb = rx.skb;
-
-	if (sta && !(sta->flags & (WLAN_STA_WDS | WLAN_STA_ASSOC_AP)) &&
-	    !atomic_read(&local->iff_promiscs) &&
-	    !is_multicast_ether_addr(hdr->addr1)) {
-		rx.flags |= IEEE80211_TXRXD_RXRA_MATCH;
-		ieee80211_invoke_rx_handlers(local, local->rx_handlers, &rx,
-					     rx.sta);
-		sta_info_put(sta);
-		rcu_read_unlock();
-		return;
-	}
+	ieee80211_parse_qos(&rx);
+	ieee80211_verify_ip_alignment(&rx);
 
-	bssid = ieee80211_get_bssid(hdr, skb->len);
+	skb = rx.skb;
 
 	list_for_each_entry_rcu(sdata, &local->interfaces, list) {
 		if (!netif_running(sdata->dev))
 			continue;
 
-		if (sdata->type == IEEE80211_IF_TYPE_MNTR)
+		if (sdata->vif.type == IEEE80211_IF_TYPE_MNTR)
 			continue;
 
+		bssid = ieee80211_get_bssid(hdr, skb->len, sdata->vif.type);
 		rx.flags |= IEEE80211_TXRXD_RXRA_MATCH;
-		prepres = prepare_for_handlers(sdata, bssid, &rx, hdr);
-		/* prepare_for_handlers can change sta */
-		sta = rx.sta;
+		prepares = prepare_for_handlers(sdata, bssid, &rx, hdr);
 
-		if (!prepres)
+		if (!prepares)
 			continue;
 
 		/*
@@ -1536,27 +1837,266 @@ void __ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb,
 				       prev->dev->name);
 			continue;
 		}
-		rx.skb = skb_new;
-		rx.dev = prev->dev;
-		rx.sdata = prev;
-		ieee80211_invoke_rx_handlers(local, local->rx_handlers,
-					     &rx, sta);
+		rx.fc = le16_to_cpu(hdr->frame_control);
+		ieee80211_invoke_rx_handlers(prev, &rx, skb_new);
 		prev = sdata;
 	}
 	if (prev) {
-		rx.skb = skb;
-		rx.dev = prev->dev;
-		rx.sdata = prev;
-		ieee80211_invoke_rx_handlers(local, local->rx_handlers,
-					     &rx, sta);
+		rx.fc = le16_to_cpu(hdr->frame_control);
+		ieee80211_invoke_rx_handlers(prev, &rx, skb);
 	} else
 		dev_kfree_skb(skb);
 
  end:
-	rcu_read_unlock();
+	if (rx.sta)
+		sta_info_put(rx.sta);
+}
 
+#define SEQ_MODULO 0x1000
+#define SEQ_MASK   0xfff
+
+static inline int seq_less(u16 sq1, u16 sq2)
+{
+	return (((sq1 - sq2) & SEQ_MASK) > (SEQ_MODULO >> 1));
+}
+
+static inline u16 seq_inc(u16 sq)
+{
+	return ((sq + 1) & SEQ_MASK);
+}
+
+static inline u16 seq_sub(u16 sq1, u16 sq2)
+{
+	return ((sq1 - sq2) & SEQ_MASK);
+}
+
+
+/*
+ * As it function blongs to Rx path it must be called with
+ * the proper rcu_read_lock protection for its flow.
+ */
+u8 ieee80211_sta_manage_reorder_buf(struct ieee80211_hw *hw,
+				struct tid_ampdu_rx *tid_agg_rx,
+				struct sk_buff *skb, u16 mpdu_seq_num,
+				int bar_req)
+{
+	struct ieee80211_local *local = hw_to_local(hw);
+	struct ieee80211_rx_status status;
+	u16 head_seq_num, buf_size;
+	int index;
+	u32 pkt_load;
+	struct ieee80211_supported_band *sband;
+	struct ieee80211_rate *rate;
+
+	buf_size = tid_agg_rx->buf_size;
+	head_seq_num = tid_agg_rx->head_seq_num;
+
+	/* frame with out of date sequence number */
+	if (seq_less(mpdu_seq_num, head_seq_num)) {
+		dev_kfree_skb(skb);
+		return 1;
+	}
+
+	/* if frame sequence number exceeds our buffering window size or
+	 * block Ack Request arrived - release stored frames */
+	if ((!seq_less(mpdu_seq_num, head_seq_num + buf_size)) || (bar_req)) {
+		/* new head to the ordering buffer */
+		if (bar_req)
+			head_seq_num = mpdu_seq_num;
+		else
+			head_seq_num =
+				seq_inc(seq_sub(mpdu_seq_num, buf_size));
+		/* release stored frames up to new head to stack */
+		while (seq_less(tid_agg_rx->head_seq_num, head_seq_num)) {
+			index = seq_sub(tid_agg_rx->head_seq_num,
+				tid_agg_rx->ssn)
+				% tid_agg_rx->buf_size;
+
+			if (tid_agg_rx->reorder_buf[index]) {
+				/* release the reordered frames to stack */
+				memcpy(&status,
+					tid_agg_rx->reorder_buf[index]->cb,
+					sizeof(status));
+				sband = local->hw.wiphy->bands[status.band];
+				rate = &sband->bitrates[status.rate_idx];
+				pkt_load = ieee80211_rx_load_stats(local,
+						tid_agg_rx->reorder_buf[index],
+						&status, rate);
+				__ieee80211_rx_handle_packet(hw,
+					tid_agg_rx->reorder_buf[index],
+					&status, pkt_load, rate);
+				tid_agg_rx->stored_mpdu_num--;
+				tid_agg_rx->reorder_buf[index] = NULL;
+			}
+			tid_agg_rx->head_seq_num =
+				seq_inc(tid_agg_rx->head_seq_num);
+		}
+		if (bar_req)
+			return 1;
+	}
+
+	/* now the new frame is always in the range of the reordering */
+	/* buffer window */
+	index = seq_sub(mpdu_seq_num, tid_agg_rx->ssn)
+				% tid_agg_rx->buf_size;
+	/* check if we already stored this frame */
+	if (tid_agg_rx->reorder_buf[index]) {
+		dev_kfree_skb(skb);
+		return 1;
+	}
+
+	/* if arrived mpdu is in the right order and nothing else stored */
+	/* release it immediately */
+	if (mpdu_seq_num == tid_agg_rx->head_seq_num &&
+			tid_agg_rx->stored_mpdu_num == 0) {
+		tid_agg_rx->head_seq_num =
+			seq_inc(tid_agg_rx->head_seq_num);
+		return 0;
+	}
+
+	/* put the frame in the reordering buffer */
+	tid_agg_rx->reorder_buf[index] = skb;
+	tid_agg_rx->stored_mpdu_num++;
+	/* release the buffer until next missing frame */
+	index = seq_sub(tid_agg_rx->head_seq_num, tid_agg_rx->ssn)
+						% tid_agg_rx->buf_size;
+	while (tid_agg_rx->reorder_buf[index]) {
+		/* release the reordered frame back to stack */
+		memcpy(&status, tid_agg_rx->reorder_buf[index]->cb,
+			sizeof(status));
+		sband = local->hw.wiphy->bands[status.band];
+		rate = &sband->bitrates[status.rate_idx];
+		pkt_load = ieee80211_rx_load_stats(local,
+					tid_agg_rx->reorder_buf[index],
+					&status, rate);
+		__ieee80211_rx_handle_packet(hw, tid_agg_rx->reorder_buf[index],
+					     &status, pkt_load, rate);
+		tid_agg_rx->stored_mpdu_num--;
+		tid_agg_rx->reorder_buf[index] = NULL;
+		tid_agg_rx->head_seq_num = seq_inc(tid_agg_rx->head_seq_num);
+		index =	seq_sub(tid_agg_rx->head_seq_num,
+			tid_agg_rx->ssn) % tid_agg_rx->buf_size;
+	}
+	return 1;
+}
+
+static u8 ieee80211_rx_reorder_ampdu(struct ieee80211_local *local,
+				     struct sk_buff *skb)
+{
+	struct ieee80211_hw *hw = &local->hw;
+	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
+	struct sta_info *sta;
+	struct tid_ampdu_rx *tid_agg_rx;
+	u16 fc, sc;
+	u16 mpdu_seq_num;
+	u8 ret = 0, *qc;
+	int tid;
+
+	sta = sta_info_get(local, hdr->addr2);
+	if (!sta)
+		return ret;
+
+	fc = le16_to_cpu(hdr->frame_control);
+
+	/* filter the QoS data rx stream according to
+	 * STA/TID and check if this STA/TID is on aggregation */
+	if (!WLAN_FC_IS_QOS_DATA(fc))
+		goto end_reorder;
+
+	qc = skb->data + ieee80211_get_hdrlen(fc) - QOS_CONTROL_LEN;
+	tid = qc[0] & QOS_CONTROL_TID_MASK;
+	tid_agg_rx = &(sta->ampdu_mlme.tid_rx[tid]);
+
+	if (tid_agg_rx->state != HT_AGG_STATE_OPERATIONAL)
+		goto end_reorder;
+
+	/* null data frames are excluded */
+	if (unlikely(fc & IEEE80211_STYPE_NULLFUNC))
+		goto end_reorder;
+
+	/* new un-ordered ampdu frame - process it */
+
+	/* reset session timer */
+	if (tid_agg_rx->timeout) {
+		unsigned long expires =
+			jiffies + (tid_agg_rx->timeout / 1000) * HZ;
+		mod_timer(&tid_agg_rx->session_timer, expires);
+	}
+
+	/* if this mpdu is fragmented - terminate rx aggregation session */
+	sc = le16_to_cpu(hdr->seq_ctrl);
+	if (sc & IEEE80211_SCTL_FRAG) {
+		ieee80211_sta_stop_rx_ba_session(sta->dev, sta->addr,
+			tid, 0, WLAN_REASON_QSTA_REQUIRE_SETUP);
+		ret = 1;
+		goto end_reorder;
+	}
+
+	/* according to mpdu sequence number deal with reordering buffer */
+	mpdu_seq_num = (sc & IEEE80211_SCTL_SEQ) >> 4;
+	ret = ieee80211_sta_manage_reorder_buf(hw, tid_agg_rx, skb,
+						mpdu_seq_num, 0);
+end_reorder:
 	if (sta)
 		sta_info_put(sta);
+	return ret;
+}
+
+/*
+ * This is the receive path handler. It is called by a low level driver when an
+ * 802.11 MPDU is received from the hardware.
+ */
+void __ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb,
+		    struct ieee80211_rx_status *status)
+{
+	struct ieee80211_local *local = hw_to_local(hw);
+	u32 pkt_load;
+	struct ieee80211_rate *rate = NULL;
+	struct ieee80211_supported_band *sband;
+
+	if (status->band < 0 ||
+	    status->band > IEEE80211_NUM_BANDS) {
+		WARN_ON(1);
+		return;
+	}
+
+	sband = local->hw.wiphy->bands[status->band];
+
+	if (!sband ||
+	    status->rate_idx < 0 ||
+	    status->rate_idx >= sband->n_bitrates) {
+		WARN_ON(1);
+		return;
+	}
+
+	rate = &sband->bitrates[status->rate_idx];
+
+	/*
+	 * key references and virtual interfaces are protected using RCU
+	 * and this requires that we are in a read-side RCU section during
+	 * receive processing
+	 */
+	rcu_read_lock();
+
+	/*
+	 * Frames with failed FCS/PLCP checksum are not returned,
+	 * all other frames are returned without radiotap header
+	 * if it was previously present.
+	 * Also, frames with less than 16 bytes are dropped.
+	 */
+	skb = ieee80211_rx_monitor(local, skb, status, rate);
+	if (!skb) {
+		rcu_read_unlock();
+		return;
+	}
+
+	pkt_load = ieee80211_rx_load_stats(local, skb, status, rate);
+	local->channel_use_raw += pkt_load;
+
+	if (!ieee80211_rx_reorder_ampdu(local, skb))
+		__ieee80211_rx_handle_packet(hw, skb, status, pkt_load, rate);
+
+	rcu_read_unlock();
 }
 EXPORT_SYMBOL(__ieee80211_rx);
 
diff --git a/package/mac80211/src/net/mac80211/sta_info.c b/package/mac80211/src/net/mac80211/sta_info.c
index 4ed1b60bb1..6b53783966 100644
--- a/package/mac80211/src/net/mac80211/sta_info.c
+++ b/package/mac80211/src/net/mac80211/sta_info.c
@@ -14,6 +14,7 @@
 #include <linux/slab.h>
 #include <linux/skbuff.h>
 #include <linux/if_arp.h>
+#include <linux/timer.h>
 
 #include <net/mac80211.h>
 #include "ieee80211_i.h"
@@ -73,36 +74,13 @@ struct sta_info *sta_info_get(struct ieee80211_local *local, u8 *addr)
 }
 EXPORT_SYMBOL(sta_info_get);
 
-int sta_info_min_txrate_get(struct ieee80211_local *local)
-{
-	struct sta_info *sta;
-	struct ieee80211_hw_mode *mode;
-	int min_txrate = 9999999;
-	int i;
-
-	read_lock_bh(&local->sta_lock);
-	mode = local->oper_hw_mode;
-	for (i = 0; i < STA_HASH_SIZE; i++) {
-		sta = local->sta_hash[i];
-		while (sta) {
-			if (sta->txrate < min_txrate)
-				min_txrate = sta->txrate;
-			sta = sta->hnext;
-		}
-	}
-	read_unlock_bh(&local->sta_lock);
-	if (min_txrate == 9999999)
-		min_txrate = 0;
-
-	return mode->rates[min_txrate].rate;
-}
-
 
 static void sta_info_release(struct kref *kref)
 {
 	struct sta_info *sta = container_of(kref, struct sta_info, kref);
 	struct ieee80211_local *local = sta->local;
 	struct sk_buff *skb;
+	int i;
 
 	/* free sta structure; it has already been removed from
 	 * hash table etc. external structures. Make sure that all
@@ -115,6 +93,10 @@ static void sta_info_release(struct kref *kref)
 	while ((skb = skb_dequeue(&sta->tx_filtered)) != NULL) {
 		dev_kfree_skb_any(skb);
 	}
+	for (i = 0; i <  STA_TID_NUM; i++) {
+		del_timer_sync(&sta->ampdu_mlme.tid_rx[i].session_timer);
+		del_timer_sync(&sta->ampdu_mlme.tid_tx[i].addba_resp_timer);
+	}
 	rate_control_free_sta(sta->rate_ctrl, sta->rate_ctrl_priv);
 	rate_control_put(sta->rate_ctrl);
 	kfree(sta);
@@ -132,6 +114,8 @@ struct sta_info * sta_info_add(struct ieee80211_local *local,
 			       struct net_device *dev, u8 *addr, gfp_t gfp)
 {
 	struct sta_info *sta;
+	int i;
+	DECLARE_MAC_BUF(mac);
 
 	sta = kzalloc(sizeof(*sta), gfp);
 	if (!sta)
@@ -150,6 +134,28 @@ struct sta_info * sta_info_add(struct ieee80211_local *local,
 	memcpy(sta->addr, addr, ETH_ALEN);
 	sta->local = local;
 	sta->dev = dev;
+	spin_lock_init(&sta->ampdu_mlme.ampdu_rx);
+	spin_lock_init(&sta->ampdu_mlme.ampdu_tx);
+	for (i = 0; i < STA_TID_NUM; i++) {
+		/* timer_to_tid must be initialized with identity mapping to
+		 * enable session_timer's data differentiation. refer to
+		 * sta_rx_agg_session_timer_expired for useage */
+		sta->timer_to_tid[i] = i;
+		/* tid to tx queue: initialize according to HW (0 is valid) */
+		sta->tid_to_tx_q[i] = local->hw.queues;
+		/* rx timers */
+		sta->ampdu_mlme.tid_rx[i].session_timer.function =
+			sta_rx_agg_session_timer_expired;
+		sta->ampdu_mlme.tid_rx[i].session_timer.data =
+			(unsigned long)&sta->timer_to_tid[i];
+		init_timer(&sta->ampdu_mlme.tid_rx[i].session_timer);
+		/* tx timers */
+		sta->ampdu_mlme.tid_tx[i].addba_resp_timer.function =
+			sta_addba_resp_timer_expired;
+		sta->ampdu_mlme.tid_tx[i].addba_resp_timer.data =
+			(unsigned long)&sta->timer_to_tid[i];
+		init_timer(&sta->ampdu_mlme.tid_tx[i].addba_resp_timer);
+	}
 	skb_queue_head_init(&sta->ps_tx_buf);
 	skb_queue_head_init(&sta->tx_filtered);
 	__sta_info_get(sta);	/* sta used by caller, decremented by
@@ -158,14 +164,21 @@ struct sta_info * sta_info_add(struct ieee80211_local *local,
 	list_add(&sta->list, &local->sta_list);
 	local->num_sta++;
 	sta_info_hash_add(local, sta);
-	if (local->ops->sta_notify)
-		local->ops->sta_notify(local_to_hw(local), dev->ifindex,
-					STA_NOTIFY_ADD, addr);
+	if (local->ops->sta_notify) {
+		struct ieee80211_sub_if_data *sdata;
+
+		sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+		if (sdata->vif.type == IEEE80211_IF_TYPE_VLAN)
+			sdata = sdata->u.vlan.ap;
+
+		local->ops->sta_notify(local_to_hw(local), &sdata->vif,
+				       STA_NOTIFY_ADD, addr);
+	}
 	write_unlock_bh(&local->sta_lock);
 
 #ifdef CONFIG_MAC80211_VERBOSE_DEBUG
-	printk(KERN_DEBUG "%s: Added STA " MAC_FMT "\n",
-	       wiphy_name(local->hw.wiphy), MAC_ARG(addr));
+	printk(KERN_DEBUG "%s: Added STA %s\n",
+	       wiphy_name(local->hw.wiphy), print_mac(mac, addr));
 #endif /* CONFIG_MAC80211_VERBOSE_DEBUG */
 
 #ifdef CONFIG_MAC80211_DEBUGFS
@@ -204,6 +217,7 @@ void sta_info_free(struct sta_info *sta)
 {
 	struct sk_buff *skb;
 	struct ieee80211_local *local = sta->local;
+	DECLARE_MAC_BUF(mac);
 
 	might_sleep();
 
@@ -220,16 +234,24 @@ void sta_info_free(struct sta_info *sta)
 	}
 
 #ifdef CONFIG_MAC80211_VERBOSE_DEBUG
-	printk(KERN_DEBUG "%s: Removed STA " MAC_FMT "\n",
-	       wiphy_name(local->hw.wiphy), MAC_ARG(sta->addr));
+	printk(KERN_DEBUG "%s: Removed STA %s\n",
+	       wiphy_name(local->hw.wiphy), print_mac(mac, sta->addr));
 #endif /* CONFIG_MAC80211_VERBOSE_DEBUG */
 
 	ieee80211_key_free(sta->key);
 	sta->key = NULL;
 
-	if (local->ops->sta_notify)
-		local->ops->sta_notify(local_to_hw(local), sta->dev->ifindex,
-					STA_NOTIFY_REMOVE, sta->addr);
+	if (local->ops->sta_notify) {
+		struct ieee80211_sub_if_data *sdata;
+
+		sdata = IEEE80211_DEV_TO_SUB_IF(sta->dev);
+
+		if (sdata->vif.type == IEEE80211_IF_TYPE_VLAN)
+			sdata = sdata->u.vlan.ap;
+
+		local->ops->sta_notify(local_to_hw(local), &sdata->vif,
+				       STA_NOTIFY_REMOVE, sta->addr);
+	}
 
 	rate_control_remove_sta_debugfs(sta);
 	ieee80211_sta_debugfs_remove(sta);
@@ -264,6 +286,7 @@ static void sta_info_cleanup_expire_buffered(struct ieee80211_local *local,
 {
 	unsigned long flags;
 	struct sk_buff *skb;
+	DECLARE_MAC_BUF(mac);
 
 	if (skb_queue_empty(&sta->ps_tx_buf))
 		return;
@@ -282,7 +305,7 @@ static void sta_info_cleanup_expire_buffered(struct ieee80211_local *local,
 		if (skb) {
 			local->total_ps_buffered--;
 			printk(KERN_DEBUG "Buffered frame expired (STA "
-			       MAC_FMT ")\n", MAC_ARG(sta->addr));
+			       "%s)\n", print_mac(mac, sta->addr));
 			dev_kfree_skb(skb);
 		} else
 			break;
@@ -303,7 +326,8 @@ static void sta_info_cleanup(unsigned long data)
 	}
 	read_unlock_bh(&local->sta_lock);
 
-	local->sta_cleanup.expires = jiffies + STA_INFO_CLEANUP_INTERVAL;
+	local->sta_cleanup.expires =
+		round_jiffies(jiffies + STA_INFO_CLEANUP_INTERVAL);
 	add_timer(&local->sta_cleanup);
 }
 
@@ -342,7 +366,8 @@ void sta_info_init(struct ieee80211_local *local)
 	INIT_LIST_HEAD(&local->sta_list);
 
 	init_timer(&local->sta_cleanup);
-	local->sta_cleanup.expires = jiffies + STA_INFO_CLEANUP_INTERVAL;
+	local->sta_cleanup.expires =
+		round_jiffies(jiffies + STA_INFO_CLEANUP_INTERVAL);
 	local->sta_cleanup.data = (unsigned long) local;
 	local->sta_cleanup.function = sta_info_cleanup;
 
diff --git a/package/mac80211/src/net/mac80211/sta_info.h b/package/mac80211/src/net/mac80211/sta_info.h
index 8f7ebe41c0..19f3fb4129 100644
--- a/package/mac80211/src/net/mac80211/sta_info.h
+++ b/package/mac80211/src/net/mac80211/sta_info.h
@@ -15,22 +15,110 @@
 #include <linux/kref.h>
 #include "ieee80211_key.h"
 
-/* Stations flags (struct sta_info::flags) */
-#define WLAN_STA_AUTH BIT(0)
-#define WLAN_STA_ASSOC BIT(1)
-#define WLAN_STA_PS BIT(2)
-#define WLAN_STA_TIM BIT(3) /* TIM bit is on for PS stations */
-#define WLAN_STA_PERM BIT(4) /* permanent; do not remove entry on expiration */
-#define WLAN_STA_AUTHORIZED BIT(5) /* If 802.1X is used, this flag is
-				    * controlling whether STA is authorized to
-				    * send and receive non-IEEE 802.1X frames
-				    */
-#define WLAN_STA_SHORT_PREAMBLE BIT(7)
-/* whether this is an AP that we are associated with as a client */
-#define WLAN_STA_ASSOC_AP BIT(8)
-#define WLAN_STA_WME BIT(9)
-#define WLAN_STA_WDS BIT(27)
+/**
+ * enum ieee80211_sta_info_flags - Stations flags
+ *
+ * These flags are used with &struct sta_info's @flags member.
+ *
+ * @WLAN_STA_AUTH: Station is authenticated.
+ * @WLAN_STA_ASSOC: Station is associated.
+ * @WLAN_STA_PS: Station is in power-save mode
+ * @WLAN_STA_TIM: TIM bit is on for this PS station (traffic buffered)
+ * @WLAN_STA_AUTHORIZED: Station is authorized to send/receive traffic.
+ *	This bit is always checked so needs to be enabled for all stations
+ *	when virtual port control is not in use.
+ * @WLAN_STA_SHORT_PREAMBLE: Station is capable of receiving short-preamble
+ *	frames.
+ * @WLAN_STA_ASSOC_AP: We're associated to that station, it is an AP.
+ * @WLAN_STA_WME: Station is a QoS-STA.
+ * @WLAN_STA_WDS: Station is one of our WDS peers.
+ */
+enum ieee80211_sta_info_flags {
+	WLAN_STA_AUTH		= 1<<0,
+	WLAN_STA_ASSOC		= 1<<1,
+	WLAN_STA_PS		= 1<<2,
+	WLAN_STA_TIM		= 1<<3,
+	WLAN_STA_AUTHORIZED	= 1<<4,
+	WLAN_STA_SHORT_PREAMBLE	= 1<<5,
+	WLAN_STA_ASSOC_AP	= 1<<6,
+	WLAN_STA_WME		= 1<<7,
+	WLAN_STA_WDS		= 1<<8,
+};
+
+#define STA_TID_NUM 16
+#define ADDBA_RESP_INTERVAL HZ
+#define HT_AGG_MAX_RETRIES		(0x3)
 
+#define HT_AGG_STATE_INITIATOR_SHIFT	(4)
+
+#define HT_ADDBA_REQUESTED_MSK		BIT(0)
+#define HT_ADDBA_DRV_READY_MSK		BIT(1)
+#define HT_ADDBA_RECEIVED_MSK		BIT(2)
+#define HT_AGG_STATE_REQ_STOP_BA_MSK	BIT(3)
+#define HT_AGG_STATE_INITIATOR_MSK      BIT(HT_AGG_STATE_INITIATOR_SHIFT)
+#define HT_AGG_STATE_IDLE		(0x0)
+#define HT_AGG_STATE_OPERATIONAL	(HT_ADDBA_REQUESTED_MSK |	\
+					 HT_ADDBA_DRV_READY_MSK |	\
+					 HT_ADDBA_RECEIVED_MSK)
+
+/**
+ * struct tid_ampdu_tx - TID aggregation information (Tx).
+ *
+ * @state: TID's state in session state machine.
+ * @dialog_token: dialog token for aggregation session
+ * @ssn: Starting Sequence Number expected to be aggregated.
+ * @addba_resp_timer: timer for peer's response to addba request
+ * @addba_req_num: number of times addBA request has been sent.
+ */
+struct tid_ampdu_tx {
+	u8 state;
+	u8 dialog_token;
+	u16 ssn;
+	struct timer_list addba_resp_timer;
+	u8 addba_req_num;
+};
+
+/**
+ * struct tid_ampdu_rx - TID aggregation information (Rx).
+ *
+ * @state: TID's state in session state machine.
+ * @dialog_token: dialog token for aggregation session
+ * @ssn: Starting Sequence Number expected to be aggregated.
+ * @buf_size: buffer size for incoming A-MPDUs
+ * @timeout: reset timer value.
+ * @head_seq_num: head sequence number in reordering buffer.
+ * @stored_mpdu_num: number of MPDUs in reordering buffer
+ * @reorder_buf: buffer to reorder incoming aggregated MPDUs
+ * @session_timer: check if peer keeps Tx-ing on the TID (by timeout value)
+ */
+struct tid_ampdu_rx {
+	u8 state;
+	u8 dialog_token;
+	u16 ssn;
+	u16 buf_size;
+	u16 timeout;
+	u16 head_seq_num;
+	u16 stored_mpdu_num;
+	struct sk_buff **reorder_buf;
+	struct timer_list session_timer;
+};
+
+/**
+ * struct sta_ampdu_mlme - STA aggregation information.
+ *
+ * @tid_rx: aggregation info for Rx per TID
+ * @tid_tx: aggregation info for Tx per TID
+ * @ampdu_rx: for locking sections in aggregation Rx flow
+ * @ampdu_tx: for locking sectionsi in aggregation Tx flow
+ * @dialog_token_allocator: dialog token enumerator for each new session;
+ */
+struct sta_ampdu_mlme {
+	struct tid_ampdu_rx tid_rx[STA_TID_NUM];
+	struct tid_ampdu_tx tid_tx[STA_TID_NUM];
+	spinlock_t ampdu_rx;
+	spinlock_t ampdu_tx;
+	u8 dialog_token_allocator;
+};
 
 struct sta_info {
 	struct kref kref;
@@ -59,10 +147,11 @@ struct sta_info {
 	unsigned int wep_weak_iv_count; /* number of RX frames with weak IV */
 
 	unsigned long last_rx;
-	u32 supp_rates; /* bitmap of supported rates in local->curr_rates */
-	int txrate; /* index in local->curr_rates */
-	int last_txrate; /* last rate used to send a frame to this STA */
-	int last_nonerp_idx;
+	/* bitmap of supported rates per band */
+	u64 supp_rates[IEEE80211_NUM_BANDS];
+	int txrate_idx;
+	/* last rates used to send a frame to this STA */
+	int last_txrate_idx, last_nonerp_txrate_idx;
 
 	struct net_device *dev; /* which net device is this station associated
 				 * to */
@@ -99,6 +188,12 @@ struct sta_info {
 
 	u16 listen_interval;
 
+	struct ieee80211_ht_info ht_info; /* 802.11n HT capabilities
+					     of this STA */
+	struct sta_ampdu_mlme ampdu_mlme;
+	u8 timer_to_tid[STA_TID_NUM];	/* convert timer id to tid */
+	u8 tid_to_tx_q[STA_TID_NUM];	/* map tid to tx queue */
+
 #ifdef CONFIG_MAC80211_DEBUGFS
 	struct sta_info_debugfsdentries {
 		struct dentry *dir;
@@ -112,6 +207,7 @@ struct sta_info {
 		struct dentry *wme_rx_queue;
 		struct dentry *wme_tx_queue;
 #endif
+		struct dentry *agg_status;
 	} debugfs;
 #endif
 };
@@ -141,7 +237,6 @@ static inline void __sta_info_get(struct sta_info *sta)
 }
 
 struct sta_info * sta_info_get(struct ieee80211_local *local, u8 *addr);
-int sta_info_min_txrate_get(struct ieee80211_local *local);
 void sta_info_put(struct sta_info *sta);
 struct sta_info * sta_info_add(struct ieee80211_local *local,
 			       struct net_device *dev, u8 *addr, gfp_t gfp);
diff --git a/package/mac80211/src/net/mac80211/tkip.c b/package/mac80211/src/net/mac80211/tkip.c
index 876cbe3710..3abe194e4d 100644
--- a/package/mac80211/src/net/mac80211/tkip.c
+++ b/package/mac80211/src/net/mac80211/tkip.c
@@ -276,9 +276,10 @@ int ieee80211_tkip_decrypt_data(struct crypto_blkcipher *tfm,
 	     (iv32 == key->u.tkip.iv32_rx[queue] &&
 	      iv16 <= key->u.tkip.iv16_rx[queue]))) {
 #ifdef CONFIG_TKIP_DEBUG
+		DECLARE_MAC_BUF(mac);
 		printk(KERN_DEBUG "TKIP replay detected for RX frame from "
-		       MAC_FMT " (RX IV (%04x,%02x) <= prev. IV (%04x,%02x)\n",
-		       MAC_ARG(ta),
+		       "%s (RX IV (%04x,%02x) <= prev. IV (%04x,%02x)\n",
+		       print_mac(mac, ta),
 		       iv32, iv16, key->u.tkip.iv32_rx[queue],
 		       key->u.tkip.iv16_rx[queue]);
 #endif /* CONFIG_TKIP_DEBUG */
@@ -300,8 +301,9 @@ int ieee80211_tkip_decrypt_data(struct crypto_blkcipher *tfm,
 #ifdef CONFIG_TKIP_DEBUG
 		{
 			int i;
-			printk(KERN_DEBUG "TKIP decrypt: Phase1 TA=" MAC_FMT
-			       " TK=", MAC_ARG(ta));
+			DECLARE_MAC_BUF(mac);
+			printk(KERN_DEBUG "TKIP decrypt: Phase1 TA=%s"
+			       " TK=", print_mac(mac, ta));
 			for (i = 0; i < 16; i++)
 				printk("%02x ",
 				       key->conf.key[
diff --git a/package/mac80211/src/net/mac80211/tx.c b/package/mac80211/src/net/mac80211/tx.c
index 957ec3c830..181d97015f 100644
--- a/package/mac80211/src/net/mac80211/tx.c
+++ b/package/mac80211/src/net/mac80211/tx.c
@@ -18,6 +18,7 @@
 #include <linux/etherdevice.h>
 #include <linux/bitmap.h>
 #include <linux/rcupdate.h>
+#include <net/net_namespace.h>
 #include <net/ieee80211_radiotap.h>
 #include <net/cfg80211.h>
 #include <net/mac80211.h>
@@ -53,6 +54,7 @@ static void ieee80211_dump_frame(const char *ifname, const char *title,
 	const struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
 	u16 fc;
 	int hdrlen;
+	DECLARE_MAC_BUF(mac);
 
 	printk(KERN_DEBUG "%s: %s (len=%d)", ifname, title, skb->len);
 	if (skb->len < 4) {
@@ -68,13 +70,13 @@ static void ieee80211_dump_frame(const char *ifname, const char *title,
 		printk(" FC=0x%04x DUR=0x%04x",
 		       fc, le16_to_cpu(hdr->duration_id));
 	if (hdrlen >= 10)
-		printk(" A1=" MAC_FMT, MAC_ARG(hdr->addr1));
+		printk(" A1=%s", print_mac(mac, hdr->addr1));
 	if (hdrlen >= 16)
-		printk(" A2=" MAC_FMT, MAC_ARG(hdr->addr2));
+		printk(" A2=%s", print_mac(mac, hdr->addr2));
 	if (hdrlen >= 24)
-		printk(" A3=" MAC_FMT, MAC_ARG(hdr->addr3));
+		printk(" A3=%s", print_mac(mac, hdr->addr3));
 	if (hdrlen >= 30)
-		printk(" A4=" MAC_FMT, MAC_ARG(hdr->addr4));
+		printk(" A4=%s", print_mac(mac, hdr->addr4));
 	printk("\n");
 }
 #else /* CONFIG_MAC80211_LOWTX_FRAME_DUMP */
@@ -90,9 +92,13 @@ static u16 ieee80211_duration(struct ieee80211_txrx_data *tx, int group_addr,
 	int rate, mrate, erp, dur, i;
 	struct ieee80211_rate *txrate = tx->u.tx.rate;
 	struct ieee80211_local *local = tx->local;
-	struct ieee80211_hw_mode *mode = tx->u.tx.mode;
+	struct ieee80211_supported_band *sband;
 
-	erp = txrate->flags & IEEE80211_RATE_ERP;
+	sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
+
+	erp = 0;
+	if (tx->sdata->flags & IEEE80211_SDATA_OPERATING_GMODE)
+		erp = txrate->flags & IEEE80211_RATE_ERP_G;
 
 	/*
 	 * data and mgmt (except PS Poll):
@@ -148,20 +154,36 @@ static u16 ieee80211_duration(struct ieee80211_txrx_data *tx, int group_addr,
 	 * Mandatory rates for IEEE 802.11g PHY: 1, 2, 5.5, 11, 6, 12, 24 Mbps
 	 */
 	rate = -1;
-	mrate = 10; /* use 1 Mbps if everything fails */
-	for (i = 0; i < mode->num_rates; i++) {
-		struct ieee80211_rate *r = &mode->rates[i];
-		if (r->rate > txrate->rate)
-			break;
+	/* use lowest available if everything fails */
+	mrate = sband->bitrates[0].bitrate;
+	for (i = 0; i < sband->n_bitrates; i++) {
+		struct ieee80211_rate *r = &sband->bitrates[i];
 
-		if (IEEE80211_RATE_MODULATION(txrate->flags) !=
-		    IEEE80211_RATE_MODULATION(r->flags))
-			continue;
+		if (r->bitrate > txrate->bitrate)
+			break;
 
-		if (r->flags & IEEE80211_RATE_BASIC)
-			rate = r->rate;
-		else if (r->flags & IEEE80211_RATE_MANDATORY)
-			mrate = r->rate;
+		if (tx->sdata->basic_rates & BIT(i))
+			rate = r->bitrate;
+
+		switch (sband->band) {
+		case IEEE80211_BAND_2GHZ: {
+			u32 flag;
+			if (tx->sdata->flags & IEEE80211_SDATA_OPERATING_GMODE)
+				flag = IEEE80211_RATE_MANDATORY_G;
+			else
+				flag = IEEE80211_RATE_MANDATORY_B;
+			if (r->flags & flag)
+				mrate = r->bitrate;
+			break;
+		}
+		case IEEE80211_BAND_5GHZ:
+			if (r->flags & IEEE80211_RATE_MANDATORY_A)
+				mrate = r->bitrate;
+			break;
+		case IEEE80211_NUM_BANDS:
+			WARN_ON(1);
+			break;
+		}
 	}
 	if (rate == -1) {
 		/* No matching basic rate found; use highest suitable mandatory
@@ -174,7 +196,7 @@ static u16 ieee80211_duration(struct ieee80211_txrx_data *tx, int group_addr,
 	 * to closest integer */
 
 	dur = ieee80211_frame_duration(local, 10, rate, erp,
-		       tx->sdata->flags & IEEE80211_SDATA_SHORT_PREAMBLE);
+				tx->sdata->bss_conf.use_short_preamble);
 
 	if (next_frag_len) {
 		/* Frame is fragmented: duration increases with time needed to
@@ -182,9 +204,8 @@ static u16 ieee80211_duration(struct ieee80211_txrx_data *tx, int group_addr,
 		dur *= 2; /* ACK + SIFS */
 		/* next fragment */
 		dur += ieee80211_frame_duration(local, next_frag_len,
-				txrate->rate, erp,
-				tx->sdata->flags &
-					IEEE80211_SDATA_SHORT_PREAMBLE);
+				txrate->bitrate, erp,
+				tx->sdata->bss_conf.use_short_preamble);
 	}
 
 	return dur;
@@ -211,7 +232,7 @@ static int inline is_ieee80211_device(struct net_device *dev,
 
 /* tx handlers */
 
-static ieee80211_txrx_result
+static ieee80211_tx_result
 ieee80211_tx_h_check_assoc(struct ieee80211_txrx_data *tx)
 {
 #ifdef CONFIG_MAC80211_VERBOSE_DEBUG
@@ -221,58 +242,48 @@ ieee80211_tx_h_check_assoc(struct ieee80211_txrx_data *tx)
 	u32 sta_flags;
 
 	if (unlikely(tx->flags & IEEE80211_TXRXD_TX_INJECTED))
-		return TXRX_CONTINUE;
+		return TX_CONTINUE;
 
-	if (unlikely(tx->local->sta_scanning != 0) &&
+	if (unlikely(tx->local->sta_sw_scanning) &&
 	    ((tx->fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_MGMT ||
 	     (tx->fc & IEEE80211_FCTL_STYPE) != IEEE80211_STYPE_PROBE_REQ))
-		return TXRX_DROP;
+		return TX_DROP;
 
 	if (tx->flags & IEEE80211_TXRXD_TXPS_BUFFERED)
-		return TXRX_CONTINUE;
+		return TX_CONTINUE;
 
 	sta_flags = tx->sta ? tx->sta->flags : 0;
 
 	if (likely(tx->flags & IEEE80211_TXRXD_TXUNICAST)) {
 		if (unlikely(!(sta_flags & WLAN_STA_ASSOC) &&
-			     tx->sdata->type != IEEE80211_IF_TYPE_IBSS &&
+			     tx->sdata->vif.type != IEEE80211_IF_TYPE_IBSS &&
 			     (tx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA)) {
 #ifdef CONFIG_MAC80211_VERBOSE_DEBUG
+			DECLARE_MAC_BUF(mac);
 			printk(KERN_DEBUG "%s: dropped data frame to not "
-			       "associated station " MAC_FMT "\n",
-			       tx->dev->name, MAC_ARG(hdr->addr1));
+			       "associated station %s\n",
+			       tx->dev->name, print_mac(mac, hdr->addr1));
 #endif /* CONFIG_MAC80211_VERBOSE_DEBUG */
 			I802_DEBUG_INC(tx->local->tx_handlers_drop_not_assoc);
-			return TXRX_DROP;
+			return TX_DROP;
 		}
 	} else {
 		if (unlikely((tx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA &&
 			     tx->local->num_sta == 0 &&
-			     tx->sdata->type != IEEE80211_IF_TYPE_IBSS)) {
+			     tx->sdata->vif.type != IEEE80211_IF_TYPE_IBSS)) {
 			/*
 			 * No associated STAs - no need to send multicast
 			 * frames.
 			 */
-			return TXRX_DROP;
+			return TX_DROP;
 		}
-		return TXRX_CONTINUE;
+		return TX_CONTINUE;
 	}
 
-	if (unlikely(/* !injected && */ tx->sdata->ieee802_1x &&
-		     !(sta_flags & WLAN_STA_AUTHORIZED))) {
-#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
-		printk(KERN_DEBUG "%s: dropped frame to " MAC_FMT
-		       " (unauthorized port)\n", tx->dev->name,
-		       MAC_ARG(hdr->addr1));
-#endif
-		I802_DEBUG_INC(tx->local->tx_handlers_drop_unauth_port);
-		return TXRX_DROP;
-	}
-
-	return TXRX_CONTINUE;
+	return TX_CONTINUE;
 }
 
-static ieee80211_txrx_result
+static ieee80211_tx_result
 ieee80211_tx_h_sequence(struct ieee80211_txrx_data *tx)
 {
 	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)tx->skb->data;
@@ -280,7 +291,7 @@ ieee80211_tx_h_sequence(struct ieee80211_txrx_data *tx)
 	if (ieee80211_get_hdrlen(le16_to_cpu(hdr->frame_control)) >= 24)
 		ieee80211_include_sequence(tx->sdata, hdr);
 
-	return TXRX_CONTINUE;
+	return TX_CONTINUE;
 }
 
 /* This function is called whenever the AP is about to exceed the maximum limit
@@ -302,7 +313,7 @@ static void purge_old_ps_buffers(struct ieee80211_local *local)
 	list_for_each_entry_rcu(sdata, &local->interfaces, list) {
 		struct ieee80211_if_ap *ap;
 		if (sdata->dev == local->mdev ||
-		    sdata->type != IEEE80211_IF_TYPE_AP)
+		    sdata->vif.type != IEEE80211_IF_TYPE_AP)
 			continue;
 		ap = &sdata->u.ap;
 		skb = skb_dequeue(&ap->ps_bc_buf);
@@ -330,16 +341,27 @@ static void purge_old_ps_buffers(struct ieee80211_local *local)
 	       wiphy_name(local->hw.wiphy), purged);
 }
 
-static inline ieee80211_txrx_result
+static ieee80211_tx_result
 ieee80211_tx_h_multicast_ps_buf(struct ieee80211_txrx_data *tx)
 {
-	/* broadcast/multicast frame */
-	/* If any of the associated stations is in power save mode,
-	 * the frame is buffered to be sent after DTIM beacon frame */
-	if ((tx->local->hw.flags & IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING) &&
-	    tx->sdata->type != IEEE80211_IF_TYPE_WDS &&
-	    tx->sdata->bss && atomic_read(&tx->sdata->bss->num_sta_ps) &&
-	    !(tx->fc & IEEE80211_FCTL_ORDER)) {
+	/*
+	 * broadcast/multicast frame
+	 *
+	 * If any of the associated stations is in power save mode,
+	 * the frame is buffered to be sent after DTIM beacon frame.
+	 * This is done either by the hardware or us.
+	 */
+
+	/* not AP/IBSS or ordered frame */
+	if (!tx->sdata->bss || (tx->fc & IEEE80211_FCTL_ORDER))
+		return TX_CONTINUE;
+
+	/* no stations in PS mode */
+	if (!atomic_read(&tx->sdata->bss->num_sta_ps))
+		return TX_CONTINUE;
+
+	/* buffered in mac80211 */
+	if (tx->local->hw.flags & IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING) {
 		if (tx->local->total_ps_buffered >= TOTAL_MAX_TX_BUFFER)
 			purge_old_ps_buffers(tx->local);
 		if (skb_queue_len(&tx->sdata->bss->ps_bc_buf) >=
@@ -353,28 +375,32 @@ ieee80211_tx_h_multicast_ps_buf(struct ieee80211_txrx_data *tx)
 		} else
 			tx->local->total_ps_buffered++;
 		skb_queue_tail(&tx->sdata->bss->ps_bc_buf, tx->skb);
-		return TXRX_QUEUED;
+		return TX_QUEUED;
 	}
 
-	return TXRX_CONTINUE;
+	/* buffered in hardware */
+	tx->u.tx.control->flags |= IEEE80211_TXCTL_SEND_AFTER_DTIM;
+
+	return TX_CONTINUE;
 }
 
-static inline ieee80211_txrx_result
+static ieee80211_tx_result
 ieee80211_tx_h_unicast_ps_buf(struct ieee80211_txrx_data *tx)
 {
 	struct sta_info *sta = tx->sta;
+	DECLARE_MAC_BUF(mac);
 
 	if (unlikely(!sta ||
 		     ((tx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT &&
 		      (tx->fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_PROBE_RESP)))
-		return TXRX_CONTINUE;
+		return TX_CONTINUE;
 
 	if (unlikely((sta->flags & WLAN_STA_PS) && !sta->pspoll)) {
 		struct ieee80211_tx_packet_data *pkt_data;
 #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
-		printk(KERN_DEBUG "STA " MAC_FMT " aid %d: PS buffer (entries "
+		printk(KERN_DEBUG "STA %s aid %d: PS buffer (entries "
 		       "before %d)\n",
-		       MAC_ARG(sta->addr), sta->aid,
+		       print_mac(mac, sta->addr), sta->aid,
 		       skb_queue_len(&sta->ps_tx_buf));
 #endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */
 		sta->flags |= WLAN_STA_TIM;
@@ -383,9 +409,9 @@ ieee80211_tx_h_unicast_ps_buf(struct ieee80211_txrx_data *tx)
 		if (skb_queue_len(&sta->ps_tx_buf) >= STA_MAX_TX_BUFFER) {
 			struct sk_buff *old = skb_dequeue(&sta->ps_tx_buf);
 			if (net_ratelimit()) {
-				printk(KERN_DEBUG "%s: STA " MAC_FMT " TX "
+				printk(KERN_DEBUG "%s: STA %s TX "
 				       "buffer full - dropping oldest frame\n",
-				       tx->dev->name, MAC_ARG(sta->addr));
+				       tx->dev->name, print_mac(mac, sta->addr));
 			}
 			dev_kfree_skb(old);
 		} else
@@ -401,26 +427,25 @@ ieee80211_tx_h_unicast_ps_buf(struct ieee80211_txrx_data *tx)
 		pkt_data = (struct ieee80211_tx_packet_data *)tx->skb->cb;
 		pkt_data->jiffies = jiffies;
 		skb_queue_tail(&sta->ps_tx_buf, tx->skb);
-		return TXRX_QUEUED;
+		return TX_QUEUED;
 	}
 #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
 	else if (unlikely(sta->flags & WLAN_STA_PS)) {
-		printk(KERN_DEBUG "%s: STA " MAC_FMT " in PS mode, but pspoll "
+		printk(KERN_DEBUG "%s: STA %s in PS mode, but pspoll "
 		       "set -> send frame\n", tx->dev->name,
-		       MAC_ARG(sta->addr));
+		       print_mac(mac, sta->addr));
 	}
 #endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */
 	sta->pspoll = 0;
 
-	return TXRX_CONTINUE;
+	return TX_CONTINUE;
 }
 
-
-static ieee80211_txrx_result
+static ieee80211_tx_result
 ieee80211_tx_h_ps_buf(struct ieee80211_txrx_data *tx)
 {
 	if (unlikely(tx->flags & IEEE80211_TXRXD_TXPS_BUFFERED))
-		return TXRX_CONTINUE;
+		return TX_CONTINUE;
 
 	if (tx->flags & IEEE80211_TXRXD_TXUNICAST)
 		return ieee80211_tx_h_unicast_ps_buf(tx);
@@ -428,13 +453,11 @@ ieee80211_tx_h_ps_buf(struct ieee80211_txrx_data *tx)
 		return ieee80211_tx_h_multicast_ps_buf(tx);
 }
 
-
-
-
-static ieee80211_txrx_result
+static ieee80211_tx_result
 ieee80211_tx_h_select_key(struct ieee80211_txrx_data *tx)
 {
 	struct ieee80211_key *key;
+	u16 fc = tx->fc;
 
 	if (unlikely(tx->u.tx.control->flags & IEEE80211_TXCTL_DO_NOT_ENCRYPT))
 		tx->key = NULL;
@@ -443,23 +466,42 @@ ieee80211_tx_h_select_key(struct ieee80211_txrx_data *tx)
 	else if ((key = rcu_dereference(tx->sdata->default_key)))
 		tx->key = key;
 	else if (tx->sdata->drop_unencrypted &&
-		 !(tx->sdata->eapol && ieee80211_is_eapol(tx->skb))) {
+		 !(tx->u.tx.control->flags & IEEE80211_TXCTL_EAPOL_FRAME) &&
+		 !(tx->flags & IEEE80211_TXRXD_TX_INJECTED)) {
 		I802_DEBUG_INC(tx->local->tx_handlers_drop_unencrypted);
-		return TXRX_DROP;
-	} else {
+		return TX_DROP;
+	} else
 		tx->key = NULL;
-		tx->u.tx.control->flags |= IEEE80211_TXCTL_DO_NOT_ENCRYPT;
-	}
 
 	if (tx->key) {
+		u16 ftype, stype;
+
 		tx->key->tx_rx_count++;
 		/* TODO: add threshold stuff again */
+
+		switch (tx->key->conf.alg) {
+		case ALG_WEP:
+			ftype = fc & IEEE80211_FCTL_FTYPE;
+			stype = fc & IEEE80211_FCTL_STYPE;
+
+			if (ftype == IEEE80211_FTYPE_MGMT &&
+			    stype == IEEE80211_STYPE_AUTH)
+				break;
+		case ALG_TKIP:
+		case ALG_CCMP:
+			if (!WLAN_FC_DATA_PRESENT(fc))
+				tx->key = NULL;
+			break;
+		}
 	}
 
-	return TXRX_CONTINUE;
+	if (!tx->key || !(tx->key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE))
+		tx->u.tx.control->flags |= IEEE80211_TXCTL_DO_NOT_ENCRYPT;
+
+	return TX_CONTINUE;
 }
 
-static ieee80211_txrx_result
+static ieee80211_tx_result
 ieee80211_tx_h_fragment(struct ieee80211_txrx_data *tx)
 {
 	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) tx->skb->data;
@@ -471,14 +513,14 @@ ieee80211_tx_h_fragment(struct ieee80211_txrx_data *tx)
 	int frag_threshold = tx->local->fragmentation_threshold;
 
 	if (!(tx->flags & IEEE80211_TXRXD_FRAGMENTED))
-		return TXRX_CONTINUE;
+		return TX_CONTINUE;
 
 	first = tx->skb;
 
 	hdrlen = ieee80211_get_hdrlen(tx->fc);
 	payload_len = first->len - hdrlen;
 	per_fragm = frag_threshold - hdrlen - FCS_LEN;
-	num_fragm = (payload_len + per_fragm - 1) / per_fragm;
+	num_fragm = DIV_ROUND_UP(payload_len, per_fragm);
 
 	frags = kzalloc(num_fragm * sizeof(struct sk_buff *), GFP_ATOMIC);
 	if (!frags)
@@ -525,7 +567,7 @@ ieee80211_tx_h_fragment(struct ieee80211_txrx_data *tx)
 	tx->u.tx.num_extra_frag = num_fragm - 1;
 	tx->u.tx.extra_frag = frags;
 
-	return TXRX_CONTINUE;
+	return TX_CONTINUE;
 
  fail:
 	printk(KERN_DEBUG "%s: failed to fragment frame\n", tx->dev->name);
@@ -536,14 +578,14 @@ ieee80211_tx_h_fragment(struct ieee80211_txrx_data *tx)
 		kfree(frags);
 	}
 	I802_DEBUG_INC(tx->local->tx_handlers_drop_fragment);
-	return TXRX_DROP;
+	return TX_DROP;
 }
 
-static ieee80211_txrx_result
+static ieee80211_tx_result
 ieee80211_tx_h_encrypt(struct ieee80211_txrx_data *tx)
 {
 	if (!tx->key)
-		return TXRX_CONTINUE;
+		return TX_CONTINUE;
 
 	switch (tx->key->conf.alg) {
 	case ALG_WEP:
@@ -556,63 +598,60 @@ ieee80211_tx_h_encrypt(struct ieee80211_txrx_data *tx)
 
 	/* not reached */
 	WARN_ON(1);
-	return TXRX_DROP;
+	return TX_DROP;
 }
 
-static ieee80211_txrx_result
+static ieee80211_tx_result
 ieee80211_tx_h_rate_ctrl(struct ieee80211_txrx_data *tx)
 {
-	struct rate_control_extra extra;
+	struct rate_selection rsel;
+	struct ieee80211_supported_band *sband;
 
-	if (likely(!tx->u.tx.rate)) {
-		memset(&extra, 0, sizeof(extra));
-		extra.mode = tx->u.tx.mode;
-		extra.ethertype = tx->ethertype;
+	sband = tx->local->hw.wiphy->bands[tx->local->hw.conf.channel->band];
 
-		tx->u.tx.rate = rate_control_get_rate(tx->local, tx->dev,
-						      tx->skb, &extra);
-		if (unlikely(extra.probe != NULL)) {
+	if (likely(!tx->u.tx.rate)) {
+		rate_control_get_rate(tx->dev, sband, tx->skb, &rsel);
+		tx->u.tx.rate = rsel.rate;
+		if (unlikely(rsel.probe)) {
 			tx->u.tx.control->flags |=
 				IEEE80211_TXCTL_RATE_CTRL_PROBE;
 			tx->flags |= IEEE80211_TXRXD_TXPROBE_LAST_FRAG;
-			tx->u.tx.control->alt_retry_rate = tx->u.tx.rate->val;
-			tx->u.tx.rate = extra.probe;
+			tx->u.tx.control->alt_retry_rate = tx->u.tx.rate;
+			tx->u.tx.rate = rsel.probe;
 		} else
-			tx->u.tx.control->alt_retry_rate = -1;
+			tx->u.tx.control->alt_retry_rate = NULL;
 
 		if (!tx->u.tx.rate)
-			return TXRX_DROP;
+			return TX_DROP;
 	} else
-		tx->u.tx.control->alt_retry_rate = -1;
+		tx->u.tx.control->alt_retry_rate = NULL;
 
-	if (tx->u.tx.mode->mode == MODE_IEEE80211G &&
-	    (tx->sdata->flags & IEEE80211_SDATA_USE_PROTECTION) &&
-	    (tx->flags & IEEE80211_TXRXD_FRAGMENTED) && extra.nonerp) {
+	if (tx->sdata->bss_conf.use_cts_prot &&
+	    (tx->flags & IEEE80211_TXRXD_FRAGMENTED) && rsel.nonerp) {
 		tx->u.tx.last_frag_rate = tx->u.tx.rate;
-		if (extra.probe)
+		if (rsel.probe)
 			tx->flags &= ~IEEE80211_TXRXD_TXPROBE_LAST_FRAG;
 		else
 			tx->flags |= IEEE80211_TXRXD_TXPROBE_LAST_FRAG;
-		tx->u.tx.rate = extra.nonerp;
-		tx->u.tx.control->rate = extra.nonerp;
+		tx->u.tx.rate = rsel.nonerp;
+		tx->u.tx.control->tx_rate = rsel.nonerp;
 		tx->u.tx.control->flags &= ~IEEE80211_TXCTL_RATE_CTRL_PROBE;
 	} else {
 		tx->u.tx.last_frag_rate = tx->u.tx.rate;
-		tx->u.tx.control->rate = tx->u.tx.rate;
+		tx->u.tx.control->tx_rate = tx->u.tx.rate;
 	}
-	tx->u.tx.control->tx_rate = tx->u.tx.rate->val;
+	tx->u.tx.control->tx_rate = tx->u.tx.rate;
 
-	return TXRX_CONTINUE;
+	return TX_CONTINUE;
 }
 
-static ieee80211_txrx_result
+static ieee80211_tx_result
 ieee80211_tx_h_misc(struct ieee80211_txrx_data *tx)
 {
 	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) tx->skb->data;
 	u16 fc = le16_to_cpu(hdr->frame_control);
 	u16 dur;
 	struct ieee80211_tx_control *control = tx->u.tx.control;
-	struct ieee80211_hw_mode *mode = tx->u.tx.mode;
 
 	if (!control->retry_limit) {
 		if (!is_multicast_ether_addr(hdr->addr1)) {
@@ -639,16 +678,16 @@ ieee80211_tx_h_misc(struct ieee80211_txrx_data *tx)
 		 * frames.
 		 * TODO: The last fragment could still use multiple retry
 		 * rates. */
-		control->alt_retry_rate = -1;
+		control->alt_retry_rate = NULL;
 	}
 
 	/* Use CTS protection for unicast frames sent using extended rates if
 	 * there are associated non-ERP stations and RTS/CTS is not configured
 	 * for the frame. */
-	if (mode->mode == MODE_IEEE80211G &&
-	    (tx->u.tx.rate->flags & IEEE80211_RATE_ERP) &&
+	if ((tx->sdata->flags & IEEE80211_SDATA_OPERATING_GMODE) &&
+	    (tx->u.tx.rate->flags & IEEE80211_RATE_ERP_G) &&
 	    (tx->flags & IEEE80211_TXRXD_TXUNICAST) &&
-	    (tx->sdata->flags & IEEE80211_SDATA_USE_PROTECTION) &&
+	    tx->sdata->bss_conf.use_cts_prot &&
 	    !(control->flags & IEEE80211_TXCTL_USE_RTS_CTS))
 		control->flags |= IEEE80211_TXCTL_USE_CTS_PROTECT;
 
@@ -656,10 +695,10 @@ ieee80211_tx_h_misc(struct ieee80211_txrx_data *tx)
 	 * short preambles at the selected rate and short preambles are
 	 * available on the network at the current point in time. */
 	if (((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA) &&
-	    (tx->u.tx.rate->flags & IEEE80211_RATE_PREAMBLE2) &&
-	    (tx->sdata->flags & IEEE80211_SDATA_SHORT_PREAMBLE) &&
+	    (tx->u.tx.rate->flags & IEEE80211_RATE_SHORT_PREAMBLE) &&
+	    tx->sdata->bss_conf.use_short_preamble &&
 	    (!tx->sta || (tx->sta->flags & WLAN_STA_SHORT_PREAMBLE))) {
-		tx->u.tx.control->tx_rate = tx->u.tx.rate->val2;
+		tx->u.tx.control->flags |= IEEE80211_TXCTL_SHORT_PREAMBLE;
 	}
 
 	/* Setup duration field for the first fragment of the frame. Duration
@@ -672,19 +711,33 @@ ieee80211_tx_h_misc(struct ieee80211_txrx_data *tx)
 
 	if ((control->flags & IEEE80211_TXCTL_USE_RTS_CTS) ||
 	    (control->flags & IEEE80211_TXCTL_USE_CTS_PROTECT)) {
-		struct ieee80211_rate *rate;
+		struct ieee80211_supported_band *sband;
+		struct ieee80211_rate *rate, *baserate;
+		int idx;
+
+		sband = tx->local->hw.wiphy->bands[
+				tx->local->hw.conf.channel->band];
 
 		/* Do not use multiple retry rates when using RTS/CTS */
-		control->alt_retry_rate = -1;
+		control->alt_retry_rate = NULL;
 
 		/* Use min(data rate, max base rate) as CTS/RTS rate */
 		rate = tx->u.tx.rate;
-		while (rate > mode->rates &&
-		       !(rate->flags & IEEE80211_RATE_BASIC))
-			rate--;
+		baserate = NULL;
 
-		control->rts_cts_rate = rate->val;
-		control->rts_rate = rate;
+		for (idx = 0; idx < sband->n_bitrates; idx++) {
+			if (sband->bitrates[idx].bitrate > rate->bitrate)
+				continue;
+			if (tx->sdata->basic_rates & BIT(idx) &&
+			    (!baserate ||
+			     (baserate->bitrate < sband->bitrates[idx].bitrate)))
+				baserate = &sband->bitrates[idx];
+		}
+
+		if (baserate)
+			control->rts_cts_rate = baserate;
+		else
+			control->rts_cts_rate = &sband->bitrates[0];
 	}
 
 	if (tx->sta) {
@@ -701,26 +754,17 @@ ieee80211_tx_h_misc(struct ieee80211_txrx_data *tx)
 		}
 	}
 
-	/*
-	 * Tell hardware to not encrypt when we had sw crypto.
-	 * Because we use the same flag to internally indicate that
-	 * no (software) encryption should be done, we have to set it
-	 * after all crypto handlers.
-	 */
-	if (tx->key && !(tx->key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE))
-		tx->u.tx.control->flags |= IEEE80211_TXCTL_DO_NOT_ENCRYPT;
-
-	return TXRX_CONTINUE;
+	return TX_CONTINUE;
 }
 
-static ieee80211_txrx_result
+static ieee80211_tx_result
 ieee80211_tx_h_load_stats(struct ieee80211_txrx_data *tx)
 {
 	struct ieee80211_local *local = tx->local;
-	struct ieee80211_hw_mode *mode = tx->u.tx.mode;
 	struct sk_buff *skb = tx->skb;
 	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
 	u32 load = 0, hdrtime;
+	struct ieee80211_rate *rate = tx->u.tx.rate;
 
 	/* TODO: this could be part of tx_status handling, so that the number
 	 * of retries would be known; TX rate should in that case be stored
@@ -731,9 +775,9 @@ ieee80211_tx_h_load_stats(struct ieee80211_txrx_data *tx)
 	/* 1 bit at 1 Mbit/s takes 1 usec; in channel_use values,
 	 * 1 usec = 1/8 * (1080 / 10) = 13.5 */
 
-	if (mode->mode == MODE_IEEE80211A ||
-	    (mode->mode == MODE_IEEE80211G &&
-	     tx->u.tx.rate->flags & IEEE80211_RATE_ERP))
+	if (tx->u.tx.channel->band == IEEE80211_BAND_5GHZ ||
+	    (tx->u.tx.channel->band == IEEE80211_BAND_2GHZ &&
+	     rate->flags & IEEE80211_RATE_ERP_G))
 		hdrtime = CHAN_UTIL_HDR_SHORT;
 	else
 		hdrtime = CHAN_UTIL_HDR_LONG;
@@ -747,14 +791,15 @@ ieee80211_tx_h_load_stats(struct ieee80211_txrx_data *tx)
 	else if (tx->u.tx.control->flags & IEEE80211_TXCTL_USE_CTS_PROTECT)
 		load += hdrtime;
 
-	load += skb->len * tx->u.tx.rate->rate_inv;
+	/* TODO: optimise again */
+	load += skb->len * CHAN_UTIL_RATE_LCM / rate->bitrate;
 
 	if (tx->u.tx.extra_frag) {
 		int i;
 		for (i = 0; i < tx->u.tx.num_extra_frag; i++) {
 			load += 2 * hdrtime;
 			load += tx->u.tx.extra_frag[i]->len *
-				tx->u.tx.rate->rate;
+				tx->u.tx.rate->bitrate;
 		}
 	}
 
@@ -765,13 +810,12 @@ ieee80211_tx_h_load_stats(struct ieee80211_txrx_data *tx)
 		tx->sta->channel_use_raw += load;
 	tx->sdata->channel_use_raw += load;
 
-	return TXRX_CONTINUE;
+	return TX_CONTINUE;
 }
 
-/* TODO: implement register/unregister functions for adding TX/RX handlers
- * into ordered list */
 
-ieee80211_tx_handler ieee80211_tx_handlers[] =
+typedef ieee80211_tx_result (*ieee80211_tx_handler)(struct ieee80211_txrx_data *);
+static ieee80211_tx_handler ieee80211_tx_handlers[] =
 {
 	ieee80211_tx_h_check_assoc,
 	ieee80211_tx_h_sequence,
@@ -792,7 +836,7 @@ ieee80211_tx_handler ieee80211_tx_handlers[] =
  * deal with packet injection down monitor interface
  * with Radiotap Header -- only called for monitor mode interface
  */
-static ieee80211_txrx_result
+static ieee80211_tx_result
 __ieee80211_parse_tx_radiotap(struct ieee80211_txrx_data *tx,
 			      struct sk_buff *skb)
 {
@@ -807,10 +851,12 @@ __ieee80211_parse_tx_radiotap(struct ieee80211_txrx_data *tx,
 	struct ieee80211_radiotap_iterator iterator;
 	struct ieee80211_radiotap_header *rthdr =
 		(struct ieee80211_radiotap_header *) skb->data;
-	struct ieee80211_hw_mode *mode = tx->local->hw.conf.mode;
+	struct ieee80211_supported_band *sband;
 	int ret = ieee80211_radiotap_iterator_init(&iterator, rthdr, skb->len);
 	struct ieee80211_tx_control *control = tx->u.tx.control;
 
+	sband = tx->local->hw.wiphy->bands[tx->local->hw.conf.channel->band];
+
 	control->flags |= IEEE80211_TXCTL_DO_NOT_ENCRYPT;
 	tx->flags |= IEEE80211_TXRXD_TX_INJECTED;
 	tx->flags &= ~IEEE80211_TXRXD_FRAGMENTED;
@@ -843,10 +889,12 @@ __ieee80211_parse_tx_radiotap(struct ieee80211_txrx_data *tx,
 			 * ieee80211 rate int is in 100kbps units eg, 0x0a=1Mbps
 			 */
 			target_rate = (*iterator.this_arg) * 5;
-			for (i = 0; i < mode->num_rates; i++) {
-				struct ieee80211_rate *r = &mode->rates[i];
+			for (i = 0; i < sband->n_bitrates; i++) {
+				struct ieee80211_rate *r;
 
-				if (r->rate == target_rate) {
+				r = &sband->bitrates[i];
+
+				if (r->bitrate == target_rate) {
 					tx->u.tx.rate = r;
 					break;
 				}
@@ -861,9 +909,11 @@ __ieee80211_parse_tx_radiotap(struct ieee80211_txrx_data *tx,
 			control->antenna_sel_tx = (*iterator.this_arg) + 1;
 			break;
 
+#if 0
 		case IEEE80211_RADIOTAP_DBM_TX_POWER:
 			control->power_level = *iterator.this_arg;
 			break;
+#endif
 
 		case IEEE80211_RADIOTAP_FLAGS:
 			if (*iterator.this_arg & IEEE80211_RADIOTAP_F_FCS) {
@@ -875,7 +925,7 @@ __ieee80211_parse_tx_radiotap(struct ieee80211_txrx_data *tx,
 				 * on transmission
 				 */
 				if (skb->len < (iterator.max_length + FCS_LEN))
-					return TXRX_DROP;
+					return TX_DROP;
 
 				skb_trim(skb, skb->len - FCS_LEN);
 			}
@@ -898,7 +948,7 @@ __ieee80211_parse_tx_radiotap(struct ieee80211_txrx_data *tx,
 	}
 
 	if (ret != -ENOENT) /* ie, if we didn't simply run out of fields */
-		return TXRX_DROP;
+		return TX_DROP;
 
 	/*
 	 * remove the radiotap header
@@ -907,13 +957,13 @@ __ieee80211_parse_tx_radiotap(struct ieee80211_txrx_data *tx,
 	 */
 	skb_pull(skb, iterator.max_length);
 
-	return TXRX_CONTINUE;
+	return TX_CONTINUE;
 }
 
 /*
  * initialises @tx
  */
-static ieee80211_txrx_result
+static ieee80211_tx_result
 __ieee80211_tx_prepare(struct ieee80211_txrx_data *tx,
 		       struct sk_buff *skb,
 		       struct net_device *dev,
@@ -922,7 +972,6 @@ __ieee80211_tx_prepare(struct ieee80211_txrx_data *tx,
 	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
 	struct ieee80211_hdr *hdr;
 	struct ieee80211_sub_if_data *sdata;
-	ieee80211_txrx_result res = TXRX_CONTINUE;
 
 	int hdrlen;
 
@@ -940,9 +989,9 @@ __ieee80211_tx_prepare(struct ieee80211_txrx_data *tx,
 
 	/* process and remove the injection radiotap header */
 	sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-	if (unlikely(sdata->type == IEEE80211_IF_TYPE_MNTR)) {
-		if (__ieee80211_parse_tx_radiotap(tx, skb) == TXRX_DROP)
-			return TXRX_DROP;
+	if (unlikely(sdata->vif.type == IEEE80211_IF_TYPE_MNTR)) {
+		if (__ieee80211_parse_tx_radiotap(tx, skb) == TX_DROP)
+			return TX_DROP;
 
 		/*
 		 * __ieee80211_parse_tx_radiotap has now removed
@@ -987,12 +1036,10 @@ __ieee80211_tx_prepare(struct ieee80211_txrx_data *tx,
 	}
 	control->flags |= IEEE80211_TXCTL_FIRST_FRAGMENT;
 
-	return res;
+	return TX_CONTINUE;
 }
 
-/* Device in tx->dev has a reference added; use dev_put(tx->dev) when
- * finished with it.
- *
+/*
  * NB: @tx is uninitialised when passed in here
  */
 static int ieee80211_tx_prepare(struct ieee80211_txrx_data *tx,
@@ -1004,7 +1051,7 @@ static int ieee80211_tx_prepare(struct ieee80211_txrx_data *tx,
 	struct net_device *dev;
 
 	pkt_data = (struct ieee80211_tx_packet_data *)skb->cb;
-	dev = dev_get_by_index(pkt_data->ifindex);
+	dev = dev_get_by_index(&init_net, pkt_data->ifindex);
 	if (unlikely(dev && !is_ieee80211_device(dev, mdev))) {
 		dev_put(dev);
 		dev = NULL;
@@ -1013,6 +1060,7 @@ static int ieee80211_tx_prepare(struct ieee80211_txrx_data *tx,
 		return -ENODEV;
 	/* initialises tx with control */
 	__ieee80211_tx_prepare(tx, skb, dev, control);
+	dev_put(dev);
 	return 0;
 }
 
@@ -1047,8 +1095,8 @@ static int __ieee80211_tx(struct ieee80211_local *local, struct sk_buff *skb,
 			if (__ieee80211_queue_stopped(local, control->queue))
 				return IEEE80211_TX_FRAG_AGAIN;
 			if (i == tx->u.tx.num_extra_frag) {
-				control->tx_rate = tx->u.tx.last_frag_hwrate;
-				control->rate = tx->u.tx.last_frag_rate;
+				control->tx_rate = tx->u.tx.last_frag_rate;
+
 				if (tx->flags & IEEE80211_TXRXD_TXPROBE_LAST_FRAG)
 					control->flags |=
 						IEEE80211_TXCTL_RATE_CTRL_PROBE;
@@ -1082,7 +1130,7 @@ static int ieee80211_tx(struct net_device *dev, struct sk_buff *skb,
 	struct sta_info *sta;
 	ieee80211_tx_handler *handler;
 	struct ieee80211_txrx_data tx;
-	ieee80211_txrx_result res = TXRX_DROP, res_prepare;
+	ieee80211_tx_result res = TX_DROP, res_prepare;
 	int ret, i;
 
 	WARN_ON(__ieee80211_queue_pending(local, control->queue));
@@ -1095,7 +1143,7 @@ static int ieee80211_tx(struct net_device *dev, struct sk_buff *skb,
 	/* initialises tx */
 	res_prepare = __ieee80211_tx_prepare(&tx, skb, dev, control);
 
-	if (res_prepare == TXRX_DROP) {
+	if (res_prepare == TX_DROP) {
 		dev_kfree_skb(skb);
 		return 0;
 	}
@@ -1107,12 +1155,12 @@ static int ieee80211_tx(struct net_device *dev, struct sk_buff *skb,
 	rcu_read_lock();
 
 	sta = tx.sta;
-	tx.u.tx.mode = local->hw.conf.mode;
+	tx.u.tx.channel = local->hw.conf.channel;
 
-	for (handler = local->tx_handlers; *handler != NULL;
+	for (handler = ieee80211_tx_handlers; *handler != NULL;
 	     handler++) {
 		res = (*handler)(&tx);
-		if (res != TXRX_CONTINUE)
+		if (res != TX_CONTINUE)
 			break;
 	}
 
@@ -1121,12 +1169,12 @@ static int ieee80211_tx(struct net_device *dev, struct sk_buff *skb,
 	if (sta)
 		sta_info_put(sta);
 
-	if (unlikely(res == TXRX_DROP)) {
+	if (unlikely(res == TX_DROP)) {
 		I802_DEBUG_INC(local->tx_handlers_drop);
 		goto drop;
 	}
 
-	if (unlikely(res == TXRX_QUEUED)) {
+	if (unlikely(res == TX_QUEUED)) {
 		I802_DEBUG_INC(local->tx_handlers_queued);
 		rcu_read_unlock();
 		return 0;
@@ -1144,7 +1192,6 @@ static int ieee80211_tx(struct net_device *dev, struct sk_buff *skb,
 			} else {
 				next_len = 0;
 				tx.u.tx.rate = tx.u.tx.last_frag_rate;
-				tx.u.tx.last_frag_hwrate = tx.u.tx.rate->val;
 			}
 			dur = ieee80211_duration(&tx, 0, next_len);
 			hdr->duration_id = cpu_to_le16(dur);
@@ -1181,7 +1228,6 @@ retry:
 		store->skb = skb;
 		store->extra_frag = tx.u.tx.extra_frag;
 		store->num_extra_frag = tx.u.tx.num_extra_frag;
-		store->last_frag_hwrate = tx.u.tx.last_frag_hwrate;
 		store->last_frag_rate = tx.u.tx.last_frag_rate;
 		store->last_frag_rate_ctrl_probe =
 			!!(tx.flags & IEEE80211_TXRXD_TXPROBE_LAST_FRAG);
@@ -1219,7 +1265,7 @@ int ieee80211_master_start_xmit(struct sk_buff *skb,
 	memset(&control, 0, sizeof(struct ieee80211_tx_control));
 
 	if (pkt_data->ifindex)
-		odev = dev_get_by_index(pkt_data->ifindex);
+		odev = dev_get_by_index(&init_net, pkt_data->ifindex);
 	if (unlikely(odev && !is_ieee80211_device(odev, dev))) {
 		dev_put(odev);
 		odev = NULL;
@@ -1243,14 +1289,18 @@ int ieee80211_master_start_xmit(struct sk_buff *skb,
 		}
 	}
 
-	control.ifindex = odev->ifindex;
-	control.type = osdata->type;
+	control.vif = &osdata->vif;
+	control.type = osdata->vif.type;
 	if (pkt_data->flags & IEEE80211_TXPD_REQ_TX_STATUS)
 		control.flags |= IEEE80211_TXCTL_REQ_TX_STATUS;
 	if (pkt_data->flags & IEEE80211_TXPD_DO_NOT_ENCRYPT)
 		control.flags |= IEEE80211_TXCTL_DO_NOT_ENCRYPT;
 	if (pkt_data->flags & IEEE80211_TXPD_REQUEUE)
 		control.flags |= IEEE80211_TXCTL_REQUEUE;
+	if (pkt_data->flags & IEEE80211_TXPD_EAPOL_FRAME)
+		control.flags |= IEEE80211_TXCTL_EAPOL_FRAME;
+	if (pkt_data->flags & IEEE80211_TXPD_AMPDU)
+		control.flags |= IEEE80211_TXCTL_AMPDU;
 	control.queue = pkt_data->queue;
 
 	ret = ieee80211_tx(odev, skb, &control);
@@ -1343,6 +1393,7 @@ int ieee80211_subif_start_xmit(struct sk_buff *skb,
 	int encaps_len, skip_header_bytes;
 	int nh_pos, h_pos;
 	struct sta_info *sta;
+	u32 sta_flags = 0;
 
 	sdata = IEEE80211_DEV_TO_SUB_IF(dev);
 	if (unlikely(skb->len < ETH_HLEN)) {
@@ -1358,10 +1409,9 @@ int ieee80211_subif_start_xmit(struct sk_buff *skb,
 	/* convert Ethernet header to proper 802.11 header (based on
 	 * operation mode) */
 	ethertype = (skb->data[12] << 8) | skb->data[13];
-	/* TODO: handling for 802.1x authorized/unauthorized port */
 	fc = IEEE80211_FTYPE_DATA | IEEE80211_STYPE_DATA;
 
-	switch (sdata->type) {
+	switch (sdata->vif.type) {
 	case IEEE80211_IF_TYPE_AP:
 	case IEEE80211_IF_TYPE_VLAN:
 		fc |= IEEE80211_FCTL_FROMDS;
@@ -1400,14 +1450,47 @@ int ieee80211_subif_start_xmit(struct sk_buff *skb,
 		goto fail;
 	}
 
-	/* receiver is QoS enabled, use a QoS type frame */
-	sta = sta_info_get(local, hdr.addr1);
-	if (sta) {
-		if (sta->flags & WLAN_STA_WME) {
-			fc |= IEEE80211_STYPE_QOS_DATA;
-			hdrlen += 2;
+	/*
+	 * There's no need to try to look up the destination
+	 * if it is a multicast address (which can only happen
+	 * in AP mode)
+	 */
+	if (!is_multicast_ether_addr(hdr.addr1)) {
+		sta = sta_info_get(local, hdr.addr1);
+		if (sta) {
+			sta_flags = sta->flags;
+			sta_info_put(sta);
 		}
-		sta_info_put(sta);
+	}
+
+	/* receiver is QoS enabled, use a QoS type frame */
+	if (sta_flags & WLAN_STA_WME) {
+		fc |= IEEE80211_STYPE_QOS_DATA;
+		hdrlen += 2;
+	}
+
+	/*
+	 * Drop unicast frames to unauthorised stations unless they are
+	 * EAPOL frames from the local station.
+	 */
+	if (unlikely(!is_multicast_ether_addr(hdr.addr1) &&
+		     !(sta_flags & WLAN_STA_AUTHORIZED) &&
+		     !(ethertype == ETH_P_PAE &&
+		       compare_ether_addr(dev->dev_addr,
+					  skb->data + ETH_ALEN) == 0))) {
+#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
+		DECLARE_MAC_BUF(mac);
+
+		if (net_ratelimit())
+			printk(KERN_DEBUG "%s: dropped frame to %s"
+			       " (unauthorized port)\n", dev->name,
+			       print_mac(mac, hdr.addr1));
+#endif
+
+		I802_DEBUG_INC(local->tx_handlers_drop_unauth_port);
+
+		ret = 0;
+		goto fail;
 	}
 
 	hdr.frame_control = cpu_to_le16(fc);
@@ -1498,6 +1581,8 @@ int ieee80211_subif_start_xmit(struct sk_buff *skb,
 	pkt_data = (struct ieee80211_tx_packet_data *)skb->cb;
 	memset(pkt_data, 0, sizeof(struct ieee80211_tx_packet_data));
 	pkt_data->ifindex = dev->ifindex;
+	if (ethertype == ETH_P_PAE)
+		pkt_data->flags |= IEEE80211_TXPD_EAPOL_FRAME;
 
 	skb->dev = local->mdev;
 	dev->stats.tx_packets++;
@@ -1522,64 +1607,6 @@ int ieee80211_subif_start_xmit(struct sk_buff *skb,
 	return ret;
 }
 
-/*
- * This is the transmit routine for the 802.11 type interfaces
- * called by upper layers of the linux networking
- * stack when it has a frame to transmit
- */
-int ieee80211_mgmt_start_xmit(struct sk_buff *skb, struct net_device *dev)
-{
-	struct ieee80211_sub_if_data *sdata;
-	struct ieee80211_tx_packet_data *pkt_data;
-	struct ieee80211_hdr *hdr;
-	u16 fc;
-
-	sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-
-	if (skb->len < 10) {
-		dev_kfree_skb(skb);
-		return 0;
-	}
-
-	if (skb_headroom(skb) < sdata->local->tx_headroom) {
-		if (pskb_expand_head(skb, sdata->local->tx_headroom,
-				     0, GFP_ATOMIC)) {
-			dev_kfree_skb(skb);
-			return 0;
-		}
-	}
-
-	hdr = (struct ieee80211_hdr *) skb->data;
-	fc = le16_to_cpu(hdr->frame_control);
-
-	pkt_data = (struct ieee80211_tx_packet_data *) skb->cb;
-	memset(pkt_data, 0, sizeof(struct ieee80211_tx_packet_data));
-	pkt_data->ifindex = sdata->dev->ifindex;
-
-	skb->priority = 20; /* use hardcoded priority for mgmt TX queue */
-	skb->dev = sdata->local->mdev;
-
-	/*
-	 * We're using the protocol field of the the frame control header
-	 * to request TX callback for hostapd. BIT(1) is checked.
-	 */
-	if ((fc & BIT(1)) == BIT(1)) {
-		pkt_data->flags |= IEEE80211_TXPD_REQ_TX_STATUS;
-		fc &= ~BIT(1);
-		hdr->frame_control = cpu_to_le16(fc);
-	}
-
-	if (!(fc & IEEE80211_FCTL_PROTECTED))
-		pkt_data->flags |= IEEE80211_TXPD_DO_NOT_ENCRYPT;
-
-	dev->stats.tx_packets++;
-	dev->stats.tx_bytes += skb->len;
-
-	dev_queue_xmit(skb);
-
-	return 0;
-}
-
 /* helper functions for pending packets for when queues are stopped */
 
 void ieee80211_clear_tx_pending(struct ieee80211_local *local)
@@ -1619,7 +1646,6 @@ void ieee80211_tx_pending(unsigned long data)
 		tx.u.tx.control = &store->control;
 		tx.u.tx.extra_frag = store->extra_frag;
 		tx.u.tx.num_extra_frag = store->num_extra_frag;
-		tx.u.tx.last_frag_hwrate = store->last_frag_hwrate;
 		tx.u.tx.last_frag_rate = store->last_frag_rate;
 		tx.flags = 0;
 		if (store->last_frag_rate_ctrl_probe)
@@ -1648,7 +1674,8 @@ void ieee80211_tx_pending(unsigned long data)
 
 static void ieee80211_beacon_add_tim(struct ieee80211_local *local,
 				     struct ieee80211_if_ap *bss,
-				     struct sk_buff *skb)
+				     struct sk_buff *skb,
+				     struct beacon_data *beacon)
 {
 	u8 *pos, *tim;
 	int aid0 = 0;
@@ -1664,7 +1691,7 @@ static void ieee80211_beacon_add_tim(struct ieee80211_local *local,
 					  IEEE80211_MAX_AID+1);
 
 	if (bss->dtim_count == 0)
-		bss->dtim_count = bss->dtim_period - 1;
+		bss->dtim_count = beacon->dtim_period - 1;
 	else
 		bss->dtim_count--;
 
@@ -1672,7 +1699,7 @@ static void ieee80211_beacon_add_tim(struct ieee80211_local *local,
 	*pos++ = WLAN_EID_TIM;
 	*pos++ = 4;
 	*pos++ = bss->dtim_count;
-	*pos++ = bss->dtim_period;
+	*pos++ = beacon->dtim_period;
 
 	if (bss->dtim_count == 0 && !skb_queue_empty(&bss->ps_bc_buf))
 		aid0 = 1;
@@ -1710,7 +1737,8 @@ static void ieee80211_beacon_add_tim(struct ieee80211_local *local,
 	read_unlock_bh(&local->sta_lock);
 }
 
-struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw, int if_id,
+struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw,
+				     struct ieee80211_vif *vif,
 				     struct ieee80211_tx_control *control)
 {
 	struct ieee80211_local *local = hw_to_local(hw);
@@ -1718,81 +1746,81 @@ struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw, int if_id,
 	struct net_device *bdev;
 	struct ieee80211_sub_if_data *sdata = NULL;
 	struct ieee80211_if_ap *ap = NULL;
-	struct ieee80211_rate *rate;
-	struct rate_control_extra extra;
-	u8 *b_head, *b_tail;
-	int bh_len, bt_len;
-
-	bdev = dev_get_by_index(if_id);
-	if (bdev) {
-		sdata = IEEE80211_DEV_TO_SUB_IF(bdev);
-		ap = &sdata->u.ap;
-		dev_put(bdev);
-	}
+	struct rate_selection rsel;
+	struct beacon_data *beacon;
+	struct ieee80211_supported_band *sband;
 
-	if (!ap || sdata->type != IEEE80211_IF_TYPE_AP ||
-	    !ap->beacon_head) {
+	sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
+
+	rcu_read_lock();
+
+	sdata = vif_to_sdata(vif);
+	bdev = sdata->dev;
+	ap = &sdata->u.ap;
+
+	beacon = rcu_dereference(ap->beacon);
+
+	if (!ap || sdata->vif.type != IEEE80211_IF_TYPE_AP || !beacon) {
 #ifdef CONFIG_MAC80211_VERBOSE_DEBUG
 		if (net_ratelimit())
-			printk(KERN_DEBUG "no beacon data avail for idx=%d "
-			       "(%s)\n", if_id, bdev ? bdev->name : "N/A");
+			printk(KERN_DEBUG "no beacon data avail for %s\n",
+			       bdev->name);
 #endif /* CONFIG_MAC80211_VERBOSE_DEBUG */
-		return NULL;
+		skb = NULL;
+		goto out;
 	}
 
-	/* Assume we are generating the normal beacon locally */
-	b_head = ap->beacon_head;
-	b_tail = ap->beacon_tail;
-	bh_len = ap->beacon_head_len;
-	bt_len = ap->beacon_tail_len;
-
-	skb = dev_alloc_skb(local->tx_headroom +
-		bh_len + bt_len + 256 /* maximum TIM len */);
+	/* headroom, head length, tail length and maximum TIM length */
+	skb = dev_alloc_skb(local->tx_headroom + beacon->head_len +
+			    beacon->tail_len + 256);
 	if (!skb)
-		return NULL;
+		goto out;
 
 	skb_reserve(skb, local->tx_headroom);
-	memcpy(skb_put(skb, bh_len), b_head, bh_len);
+	memcpy(skb_put(skb, beacon->head_len), beacon->head,
+	       beacon->head_len);
 
 	ieee80211_include_sequence(sdata, (struct ieee80211_hdr *)skb->data);
 
-	ieee80211_beacon_add_tim(local, ap, skb);
+	ieee80211_beacon_add_tim(local, ap, skb, beacon);
 
-	if (b_tail) {
-		memcpy(skb_put(skb, bt_len), b_tail, bt_len);
-	}
+	if (beacon->tail)
+		memcpy(skb_put(skb, beacon->tail_len), beacon->tail,
+		       beacon->tail_len);
 
 	if (control) {
-		memset(&extra, 0, sizeof(extra));
-		extra.mode = local->oper_hw_mode;
-
-		rate = rate_control_get_rate(local, local->mdev, skb, &extra);
-		if (!rate) {
+		rate_control_get_rate(local->mdev, sband, skb, &rsel);
+		if (!rsel.rate) {
 			if (net_ratelimit()) {
-				printk(KERN_DEBUG "%s: ieee80211_beacon_get: no rate "
-				       "found\n", wiphy_name(local->hw.wiphy));
+				printk(KERN_DEBUG "%s: ieee80211_beacon_get: "
+				       "no rate found\n",
+				       wiphy_name(local->hw.wiphy));
 			}
 			dev_kfree_skb(skb);
-			return NULL;
+			skb = NULL;
+			goto out;
 		}
 
-		control->tx_rate =
-			((sdata->flags & IEEE80211_SDATA_SHORT_PREAMBLE) &&
-			(rate->flags & IEEE80211_RATE_PREAMBLE2)) ?
-			rate->val2 : rate->val;
+		control->vif = vif;
+		control->tx_rate = rsel.rate;
+		if (sdata->bss_conf.use_short_preamble &&
+		    rsel.rate->flags & IEEE80211_RATE_SHORT_PREAMBLE)
+			control->flags |= IEEE80211_TXCTL_SHORT_PREAMBLE;
 		control->antenna_sel_tx = local->hw.conf.antenna_sel_tx;
-		control->power_level = local->hw.conf.power_level;
 		control->flags |= IEEE80211_TXCTL_NO_ACK;
 		control->retry_limit = 1;
 		control->flags |= IEEE80211_TXCTL_CLEAR_DST_MASK;
 	}
 
 	ap->num_beacons++;
+
+ out:
+	rcu_read_unlock();
 	return skb;
 }
 EXPORT_SYMBOL(ieee80211_beacon_get);
 
-void ieee80211_rts_get(struct ieee80211_hw *hw, int if_id,
+void ieee80211_rts_get(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
 		       const void *frame, size_t frame_len,
 		       const struct ieee80211_tx_control *frame_txctl,
 		       struct ieee80211_rts *rts)
@@ -1802,13 +1830,14 @@ void ieee80211_rts_get(struct ieee80211_hw *hw, int if_id,
 
 	fctl = IEEE80211_FTYPE_CTL | IEEE80211_STYPE_RTS;
 	rts->frame_control = cpu_to_le16(fctl);
-	rts->duration = ieee80211_rts_duration(hw, if_id, frame_len, frame_txctl);
+	rts->duration = ieee80211_rts_duration(hw, vif, frame_len,
+					       frame_txctl);
 	memcpy(rts->ra, hdr->addr1, sizeof(rts->ra));
 	memcpy(rts->ta, hdr->addr2, sizeof(rts->ta));
 }
 EXPORT_SYMBOL(ieee80211_rts_get);
 
-void ieee80211_ctstoself_get(struct ieee80211_hw *hw, int if_id,
+void ieee80211_ctstoself_get(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
 			     const void *frame, size_t frame_len,
 			     const struct ieee80211_tx_control *frame_txctl,
 			     struct ieee80211_cts *cts)
@@ -1818,13 +1847,15 @@ void ieee80211_ctstoself_get(struct ieee80211_hw *hw, int if_id,
 
 	fctl = IEEE80211_FTYPE_CTL | IEEE80211_STYPE_CTS;
 	cts->frame_control = cpu_to_le16(fctl);
-	cts->duration = ieee80211_ctstoself_duration(hw, if_id, frame_len, frame_txctl);
+	cts->duration = ieee80211_ctstoself_duration(hw, vif,
+						     frame_len, frame_txctl);
 	memcpy(cts->ra, hdr->addr1, sizeof(cts->ra));
 }
 EXPORT_SYMBOL(ieee80211_ctstoself_get);
 
 struct sk_buff *
-ieee80211_get_buffered_bc(struct ieee80211_hw *hw, int if_id,
+ieee80211_get_buffered_bc(struct ieee80211_hw *hw,
+			  struct ieee80211_vif *vif,
 			  struct ieee80211_tx_control *control)
 {
 	struct ieee80211_local *local = hw_to_local(hw);
@@ -1832,19 +1863,28 @@ ieee80211_get_buffered_bc(struct ieee80211_hw *hw, int if_id,
 	struct sta_info *sta;
 	ieee80211_tx_handler *handler;
 	struct ieee80211_txrx_data tx;
-	ieee80211_txrx_result res = TXRX_DROP;
+	ieee80211_tx_result res = TX_DROP;
 	struct net_device *bdev;
 	struct ieee80211_sub_if_data *sdata;
 	struct ieee80211_if_ap *bss = NULL;
+	struct beacon_data *beacon;
 
-	bdev = dev_get_by_index(if_id);
-	if (bdev) {
-		sdata = IEEE80211_DEV_TO_SUB_IF(bdev);
-		bss = &sdata->u.ap;
-		dev_put(bdev);
-	}
-	if (!bss || sdata->type != IEEE80211_IF_TYPE_AP || !bss->beacon_head)
+	sdata = vif_to_sdata(vif);
+	bdev = sdata->dev;
+
+
+	if (!bss)
+		return NULL;
+
+	rcu_read_lock();
+	beacon = rcu_dereference(bss->beacon);
+
+	if (sdata->vif.type != IEEE80211_IF_TYPE_AP || !beacon ||
+	    !beacon->head) {
+		rcu_read_unlock();
 		return NULL;
+	}
+	rcu_read_unlock();
 
 	if (bss->dtim_count != 0)
 		return NULL; /* send buffered bc/mc only after DTIM beacon */
@@ -1871,21 +1911,20 @@ ieee80211_get_buffered_bc(struct ieee80211_hw *hw, int if_id,
 	}
 	sta = tx.sta;
 	tx.flags |= IEEE80211_TXRXD_TXPS_BUFFERED;
-	tx.u.tx.mode = local->hw.conf.mode;
+	tx.u.tx.channel = local->hw.conf.channel;
 
-	for (handler = local->tx_handlers; *handler != NULL; handler++) {
+	for (handler = ieee80211_tx_handlers; *handler != NULL; handler++) {
 		res = (*handler)(&tx);
-		if (res == TXRX_DROP || res == TXRX_QUEUED)
+		if (res == TX_DROP || res == TX_QUEUED)
 			break;
 	}
-	dev_put(tx.dev);
 	skb = tx.skb; /* handlers are allowed to change skb */
 
-	if (res == TXRX_DROP) {
+	if (res == TX_DROP) {
 		I802_DEBUG_INC(local->tx_handlers_drop);
 		dev_kfree_skb(skb);
 		skb = NULL;
-	} else if (res == TXRX_QUEUED) {
+	} else if (res == TX_QUEUED) {
 		I802_DEBUG_INC(local->tx_handlers_queued);
 		skb = NULL;
 	}
diff --git a/package/mac80211/src/net/mac80211/util.c b/package/mac80211/src/net/mac80211/util.c
index 27203f1b95..f64804fed0 100644
--- a/package/mac80211/src/net/mac80211/util.c
+++ b/package/mac80211/src/net/mac80211/util.c
@@ -20,7 +20,9 @@
 #include <linux/if_arp.h>
 #include <linux/wireless.h>
 #include <linux/bitmap.h>
+#include <net/net_namespace.h>
 #include <net/cfg80211.h>
+#include <net/rtnetlink.h>
 
 #include "ieee80211_i.h"
 #include "ieee80211_rate.h"
@@ -38,108 +40,22 @@ const unsigned char rfc1042_header[] =
 const unsigned char bridge_tunnel_header[] =
 	{ 0xaa, 0xaa, 0x03, 0x00, 0x00, 0xf8 };
 
-/* No encapsulation header if EtherType < 0x600 (=length) */
-static const unsigned char eapol_header[] =
-	{ 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00, 0x88, 0x8e };
 
-
-static int rate_list_match(const int *rate_list, int rate)
-{
-	int i;
-
-	if (!rate_list)
-		return 0;
-
-	for (i = 0; rate_list[i] >= 0; i++)
-		if (rate_list[i] == rate)
-			return 1;
-
-	return 0;
-}
-
-void ieee80211_prepare_rates(struct ieee80211_local *local,
-			     struct ieee80211_hw_mode *mode)
-{
-	int i;
-
-	for (i = 0; i < mode->num_rates; i++) {
-		struct ieee80211_rate *rate = &mode->rates[i];
-
-		rate->flags &= ~(IEEE80211_RATE_SUPPORTED |
-				 IEEE80211_RATE_BASIC);
-
-		if (local->supp_rates[mode->mode]) {
-			if (!rate_list_match(local->supp_rates[mode->mode],
-					     rate->rate))
-				continue;
-		}
-
-		rate->flags |= IEEE80211_RATE_SUPPORTED;
-
-		/* Use configured basic rate set if it is available. If not,
-		 * use defaults that are sane for most cases. */
-		if (local->basic_rates[mode->mode]) {
-			if (rate_list_match(local->basic_rates[mode->mode],
-					    rate->rate))
-				rate->flags |= IEEE80211_RATE_BASIC;
-		} else switch (mode->mode) {
-		case MODE_IEEE80211A:
-			if (rate->rate == 60 || rate->rate == 120 ||
-			    rate->rate == 240)
-				rate->flags |= IEEE80211_RATE_BASIC;
-			break;
-		case MODE_IEEE80211B:
-			if (rate->rate == 10 || rate->rate == 20)
-				rate->flags |= IEEE80211_RATE_BASIC;
-			break;
-		case MODE_IEEE80211G:
-			if (rate->rate == 10 || rate->rate == 20 ||
-			    rate->rate == 55 || rate->rate == 110)
-				rate->flags |= IEEE80211_RATE_BASIC;
-			break;
-		case NUM_IEEE80211_MODES:
-			/* not useful */
-			break;
-		}
-
-		/* Set ERP and MANDATORY flags based on phymode */
-		switch (mode->mode) {
-		case MODE_IEEE80211A:
-			if (rate->rate == 60 || rate->rate == 120 ||
-			    rate->rate == 240)
-				rate->flags |= IEEE80211_RATE_MANDATORY;
-			break;
-		case MODE_IEEE80211B:
-			if (rate->rate == 10)
-				rate->flags |= IEEE80211_RATE_MANDATORY;
-			break;
-		case MODE_IEEE80211G:
-			if (rate->rate == 10 || rate->rate == 20 ||
-			    rate->rate == 55 || rate->rate == 110 ||
-			    rate->rate == 60 || rate->rate == 120 ||
-			    rate->rate == 240)
-				rate->flags |= IEEE80211_RATE_MANDATORY;
-			break;
-		case NUM_IEEE80211_MODES:
-			/* not useful */
-			break;
-		}
-		if (ieee80211_is_erp_rate(mode->mode, rate->rate))
-			rate->flags |= IEEE80211_RATE_ERP;
-	}
-}
-
-u8 *ieee80211_get_bssid(struct ieee80211_hdr *hdr, size_t len)
+u8 *ieee80211_get_bssid(struct ieee80211_hdr *hdr, size_t len,
+			enum ieee80211_if_types type)
 {
 	u16 fc;
 
-	if (len < 24)
+	 /* drop ACK/CTS frames and incorrect hdr len (ctrl) */
+	if (len < 16)
 		return NULL;
 
 	fc = le16_to_cpu(hdr->frame_control);
 
 	switch (fc & IEEE80211_FCTL_FTYPE) {
 	case IEEE80211_FTYPE_DATA:
+		if (len < 24) /* drop incorrect hdr len (data) */
+			return NULL;
 		switch (fc & (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) {
 		case IEEE80211_FCTL_TODS:
 			return hdr->addr1;
@@ -152,10 +68,24 @@ u8 *ieee80211_get_bssid(struct ieee80211_hdr *hdr, size_t len)
 		}
 		break;
 	case IEEE80211_FTYPE_MGMT:
+		if (len < 24) /* drop incorrect hdr len (mgmt) */
+			return NULL;
 		return hdr->addr3;
 	case IEEE80211_FTYPE_CTL:
 		if ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_PSPOLL)
 			return hdr->addr1;
+		else if ((fc & IEEE80211_FCTL_STYPE) ==
+						IEEE80211_STYPE_BACK_REQ) {
+			switch (type) {
+			case IEEE80211_IF_TYPE_STA:
+				return hdr->addr2;
+			case IEEE80211_IF_TYPE_AP:
+			case IEEE80211_IF_TYPE_VLAN:
+				return hdr->addr1;
+			default:
+				return NULL;
+			}
+		}
 		else
 			return NULL;
 	}
@@ -216,31 +146,6 @@ int ieee80211_get_hdrlen_from_skb(const struct sk_buff *skb)
 }
 EXPORT_SYMBOL(ieee80211_get_hdrlen_from_skb);
 
-int ieee80211_is_eapol(const struct sk_buff *skb)
-{
-	const struct ieee80211_hdr *hdr;
-	u16 fc;
-	int hdrlen;
-
-	if (unlikely(skb->len < 10))
-		return 0;
-
-	hdr = (const struct ieee80211_hdr *) skb->data;
-	fc = le16_to_cpu(hdr->frame_control);
-
-	if (unlikely(!WLAN_FC_DATA_PRESENT(fc)))
-		return 0;
-
-	hdrlen = ieee80211_get_hdrlen(fc);
-
-	if (unlikely(skb->len >= hdrlen + sizeof(eapol_header) &&
-		     memcmp(skb->data + hdrlen, eapol_header,
-			    sizeof(eapol_header)) == 0))
-		return 1;
-
-	return 0;
-}
-
 void ieee80211_tx_set_iswep(struct ieee80211_txrx_data *tx)
 {
 	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) tx->skb->data;
@@ -271,7 +176,7 @@ int ieee80211_frame_duration(struct ieee80211_local *local, size_t len,
 	 * DIV_ROUND_UP() operations.
 	 */
 
-	if (local->hw.conf.phymode == MODE_IEEE80211A || erp) {
+	if (local->hw.conf.channel->band == IEEE80211_BAND_5GHZ || erp) {
 		/*
 		 * OFDM:
 		 *
@@ -311,120 +216,92 @@ int ieee80211_frame_duration(struct ieee80211_local *local, size_t len,
 }
 
 /* Exported duration function for driver use */
-__le16 ieee80211_generic_frame_duration(struct ieee80211_hw *hw, int if_id,
-					size_t frame_len, int rate)
+__le16 ieee80211_generic_frame_duration(struct ieee80211_hw *hw,
+					struct ieee80211_vif *vif,
+					size_t frame_len,
+					struct ieee80211_rate *rate)
 {
 	struct ieee80211_local *local = hw_to_local(hw);
-	struct net_device *bdev = dev_get_by_index(if_id);
-	struct ieee80211_sub_if_data *sdata;
+	struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
 	u16 dur;
 	int erp;
 
-	if (unlikely(!bdev))
-		return 0;
+	erp = 0;
+	if (sdata->flags & IEEE80211_SDATA_OPERATING_GMODE)
+		erp = rate->flags & IEEE80211_RATE_ERP_G;
 
-	sdata = IEEE80211_DEV_TO_SUB_IF(bdev);
-	erp = ieee80211_is_erp_rate(hw->conf.phymode, rate);
-	dur = ieee80211_frame_duration(local, frame_len, rate,
-		       erp, sdata->flags & IEEE80211_SDATA_SHORT_PREAMBLE);
+	dur = ieee80211_frame_duration(local, frame_len, rate->bitrate, erp,
+				       sdata->bss_conf.use_short_preamble);
 
-	dev_put(bdev);
 	return cpu_to_le16(dur);
 }
 EXPORT_SYMBOL(ieee80211_generic_frame_duration);
 
-__le16 ieee80211_rts_duration(struct ieee80211_hw *hw, int if_id,
-			      size_t frame_len,
+__le16 ieee80211_rts_duration(struct ieee80211_hw *hw,
+			      struct ieee80211_vif *vif, size_t frame_len,
 			      const struct ieee80211_tx_control *frame_txctl)
 {
 	struct ieee80211_local *local = hw_to_local(hw);
 	struct ieee80211_rate *rate;
-	struct net_device *bdev = dev_get_by_index(if_id);
-	struct ieee80211_sub_if_data *sdata;
-	int short_preamble;
+	struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
+	bool short_preamble;
 	int erp;
 	u16 dur;
 
-	if (unlikely(!bdev))
-		return 0;
+	short_preamble = sdata->bss_conf.use_short_preamble;
 
-	sdata = IEEE80211_DEV_TO_SUB_IF(bdev);
-	short_preamble = sdata->flags & IEEE80211_SDATA_SHORT_PREAMBLE;
+	rate = frame_txctl->rts_cts_rate;
 
-	rate = frame_txctl->rts_rate;
-	erp = !!(rate->flags & IEEE80211_RATE_ERP);
+	erp = 0;
+	if (sdata->flags & IEEE80211_SDATA_OPERATING_GMODE)
+		erp = rate->flags & IEEE80211_RATE_ERP_G;
 
 	/* CTS duration */
-	dur = ieee80211_frame_duration(local, 10, rate->rate,
+	dur = ieee80211_frame_duration(local, 10, rate->bitrate,
 				       erp, short_preamble);
 	/* Data frame duration */
-	dur += ieee80211_frame_duration(local, frame_len, rate->rate,
+	dur += ieee80211_frame_duration(local, frame_len, rate->bitrate,
 					erp, short_preamble);
 	/* ACK duration */
-	dur += ieee80211_frame_duration(local, 10, rate->rate,
+	dur += ieee80211_frame_duration(local, 10, rate->bitrate,
 					erp, short_preamble);
 
-	dev_put(bdev);
 	return cpu_to_le16(dur);
 }
 EXPORT_SYMBOL(ieee80211_rts_duration);
 
-__le16 ieee80211_ctstoself_duration(struct ieee80211_hw *hw, int if_id,
+__le16 ieee80211_ctstoself_duration(struct ieee80211_hw *hw,
+				    struct ieee80211_vif *vif,
 				    size_t frame_len,
 				    const struct ieee80211_tx_control *frame_txctl)
 {
 	struct ieee80211_local *local = hw_to_local(hw);
 	struct ieee80211_rate *rate;
-	struct net_device *bdev = dev_get_by_index(if_id);
-	struct ieee80211_sub_if_data *sdata;
-	int short_preamble;
+	struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
+	bool short_preamble;
 	int erp;
 	u16 dur;
 
-	if (unlikely(!bdev))
-		return 0;
+	short_preamble = sdata->bss_conf.use_short_preamble;
 
-	sdata = IEEE80211_DEV_TO_SUB_IF(bdev);
-	short_preamble = sdata->flags & IEEE80211_SDATA_SHORT_PREAMBLE;
-
-	rate = frame_txctl->rts_rate;
-	erp = !!(rate->flags & IEEE80211_RATE_ERP);
+	rate = frame_txctl->rts_cts_rate;
+	erp = 0;
+	if (sdata->flags & IEEE80211_SDATA_OPERATING_GMODE)
+		erp = rate->flags & IEEE80211_RATE_ERP_G;
 
 	/* Data frame duration */
-	dur = ieee80211_frame_duration(local, frame_len, rate->rate,
+	dur = ieee80211_frame_duration(local, frame_len, rate->bitrate,
 				       erp, short_preamble);
 	if (!(frame_txctl->flags & IEEE80211_TXCTL_NO_ACK)) {
 		/* ACK duration */
-		dur += ieee80211_frame_duration(local, 10, rate->rate,
+		dur += ieee80211_frame_duration(local, 10, rate->bitrate,
 						erp, short_preamble);
 	}
 
-	dev_put(bdev);
 	return cpu_to_le16(dur);
 }
 EXPORT_SYMBOL(ieee80211_ctstoself_duration);
 
-struct ieee80211_rate *
-ieee80211_get_rate(struct ieee80211_local *local, int phymode, int hw_rate)
-{
-	struct ieee80211_hw_mode *mode;
-	int r;
-
-	list_for_each_entry(mode, &local->modes_list, list) {
-		if (mode->mode != phymode)
-			continue;
-		for (r = 0; r < mode->num_rates; r++) {
-			struct ieee80211_rate *rate = &mode->rates[r];
-			if (rate->val == hw_rate ||
-			    (rate->flags & IEEE80211_RATE_PREAMBLE2 &&
-			     rate->val2 == hw_rate))
-				return rate;
-		}
-	}
-
-	return NULL;
-}
-
 void ieee80211_wake_queue(struct ieee80211_hw *hw, int queue)
 {
 	struct ieee80211_local *local = hw_to_local(hw);
@@ -483,3 +360,37 @@ void ieee80211_wake_queues(struct ieee80211_hw *hw)
 		ieee80211_wake_queue(hw, i);
 }
 EXPORT_SYMBOL(ieee80211_wake_queues);
+
+void ieee80211_iterate_active_interfaces(
+	struct ieee80211_hw *hw,
+	void (*iterator)(void *data, u8 *mac,
+			 struct ieee80211_vif *vif),
+	void *data)
+{
+	struct ieee80211_local *local = hw_to_local(hw);
+	struct ieee80211_sub_if_data *sdata;
+
+	rcu_read_lock();
+
+	list_for_each_entry_rcu(sdata, &local->interfaces, list) {
+		switch (sdata->vif.type) {
+		case IEEE80211_IF_TYPE_INVALID:
+		case IEEE80211_IF_TYPE_MNTR:
+		case IEEE80211_IF_TYPE_VLAN:
+			continue;
+		case IEEE80211_IF_TYPE_AP:
+		case IEEE80211_IF_TYPE_STA:
+		case IEEE80211_IF_TYPE_IBSS:
+		case IEEE80211_IF_TYPE_WDS:
+			break;
+		}
+		if (sdata->dev == local->mdev)
+			continue;
+		if (netif_running(sdata->dev))
+			iterator(data, sdata->dev->dev_addr,
+				 &sdata->vif);
+	}
+
+	rcu_read_unlock();
+}
+EXPORT_SYMBOL_GPL(ieee80211_iterate_active_interfaces);
diff --git a/package/mac80211/src/net/mac80211/wep.c b/package/mac80211/src/net/mac80211/wep.c
index 6675261e95..a33ef5cfa9 100644
--- a/package/mac80211/src/net/mac80211/wep.c
+++ b/package/mac80211/src/net/mac80211/wep.c
@@ -16,7 +16,7 @@
 #include <linux/crypto.h>
 #include <linux/err.h>
 #include <linux/mm.h>
-#include <asm/scatterlist.h>
+#include <linux/scatterlist.h>
 
 #include <net/mac80211.h>
 #include "ieee80211_i.h"
@@ -138,9 +138,7 @@ void ieee80211_wep_encrypt_data(struct crypto_blkcipher *tfm, u8 *rc4key,
 	*icv = cpu_to_le32(~crc32_le(~0, data, data_len));
 
 	crypto_blkcipher_setkey(tfm, rc4key, klen);
-	sg.page = virt_to_page(data);
-	sg.offset = offset_in_page(data);
-	sg.length = data_len + WEP_ICV_LEN;
+	sg_init_one(&sg, data, data_len + WEP_ICV_LEN);
 	crypto_blkcipher_encrypt(&desc, &sg, &sg, sg.length);
 }
 
@@ -204,9 +202,7 @@ int ieee80211_wep_decrypt_data(struct crypto_blkcipher *tfm, u8 *rc4key,
 	__le32 crc;
 
 	crypto_blkcipher_setkey(tfm, rc4key, klen);
-	sg.page = virt_to_page(data);
-	sg.offset = offset_in_page(data);
-	sg.length = data_len + WEP_ICV_LEN;
+	sg_init_one(&sg, data, data_len + WEP_ICV_LEN);
 	crypto_blkcipher_decrypt(&desc, &sg, &sg, sg.length);
 
 	crc = cpu_to_le32(~crc32_le(~0, data, data_len));
@@ -269,7 +265,8 @@ int ieee80211_wep_decrypt(struct ieee80211_local *local, struct sk_buff *skb,
 	if (ieee80211_wep_decrypt_data(local->wep_rx_tfm, rc4key, klen,
 				       skb->data + hdrlen + WEP_IV_LEN,
 				       len)) {
-		printk(KERN_DEBUG "WEP decrypt failed (ICV)\n");
+		if (net_ratelimit())
+			printk(KERN_DEBUG "WEP decrypt failed (ICV)\n");
 		ret = -1;
 	}
 
@@ -308,20 +305,22 @@ u8 * ieee80211_wep_is_weak_iv(struct sk_buff *skb, struct ieee80211_key *key)
 	return NULL;
 }
 
-ieee80211_txrx_result
+ieee80211_rx_result
 ieee80211_crypto_wep_decrypt(struct ieee80211_txrx_data *rx)
 {
 	if ((rx->fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA &&
 	    ((rx->fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_MGMT ||
 	     (rx->fc & IEEE80211_FCTL_STYPE) != IEEE80211_STYPE_AUTH))
-		return TXRX_CONTINUE;
+		return RX_CONTINUE;
 
 	if (!(rx->u.rx.status->flag & RX_FLAG_DECRYPTED)) {
 		if (ieee80211_wep_decrypt(rx->local, rx->skb, rx->key)) {
+#ifdef CONFIG_MAC80211_DEBUG
 			if (net_ratelimit())
 				printk(KERN_DEBUG "%s: RX WEP frame, decrypt "
 				       "failed\n", rx->dev->name);
-			return TXRX_DROP;
+#endif /* CONFIG_MAC80211_DEBUG */
+			return RX_DROP_UNUSABLE;
 		}
 	} else if (!(rx->u.rx.status->flag & RX_FLAG_IV_STRIPPED)) {
 		ieee80211_wep_remove_iv(rx->local, rx->skb, rx->key);
@@ -329,7 +328,7 @@ ieee80211_crypto_wep_decrypt(struct ieee80211_txrx_data *rx)
 		skb_trim(rx->skb, rx->skb->len - 4);
 	}
 
-	return TXRX_CONTINUE;
+	return RX_CONTINUE;
 }
 
 static int wep_encrypt_skb(struct ieee80211_txrx_data *tx, struct sk_buff *skb)
@@ -347,26 +346,16 @@ static int wep_encrypt_skb(struct ieee80211_txrx_data *tx, struct sk_buff *skb)
 	return 0;
 }
 
-ieee80211_txrx_result
+ieee80211_tx_result
 ieee80211_crypto_wep_encrypt(struct ieee80211_txrx_data *tx)
 {
-	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) tx->skb->data;
-	u16 fc;
-
-	fc = le16_to_cpu(hdr->frame_control);
-
-	if (((fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA &&
-	     ((fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_MGMT ||
-	      (fc & IEEE80211_FCTL_STYPE) != IEEE80211_STYPE_AUTH)))
-		return TXRX_CONTINUE;
-
 	tx->u.tx.control->iv_len = WEP_IV_LEN;
 	tx->u.tx.control->icv_len = WEP_ICV_LEN;
 	ieee80211_tx_set_iswep(tx);
 
 	if (wep_encrypt_skb(tx, tx->skb) < 0) {
 		I802_DEBUG_INC(tx->local->tx_handlers_drop_wep);
-		return TXRX_DROP;
+		return TX_DROP;
 	}
 
 	if (tx->u.tx.extra_frag) {
@@ -375,10 +364,10 @@ ieee80211_crypto_wep_encrypt(struct ieee80211_txrx_data *tx)
 			if (wep_encrypt_skb(tx, tx->u.tx.extra_frag[i]) < 0) {
 				I802_DEBUG_INC(tx->local->
 					       tx_handlers_drop_wep);
-				return TXRX_DROP;
+				return TX_DROP;
 			}
 		}
 	}
 
-	return TXRX_CONTINUE;
+	return TX_CONTINUE;
 }
diff --git a/package/mac80211/src/net/mac80211/wep.h b/package/mac80211/src/net/mac80211/wep.h
index 785fbb4e0d..43aef50cd0 100644
--- a/package/mac80211/src/net/mac80211/wep.h
+++ b/package/mac80211/src/net/mac80211/wep.h
@@ -28,9 +28,9 @@ int ieee80211_wep_decrypt(struct ieee80211_local *local, struct sk_buff *skb,
 			  struct ieee80211_key *key);
 u8 * ieee80211_wep_is_weak_iv(struct sk_buff *skb, struct ieee80211_key *key);
 
-ieee80211_txrx_result
+ieee80211_rx_result
 ieee80211_crypto_wep_decrypt(struct ieee80211_txrx_data *rx);
-ieee80211_txrx_result
+ieee80211_tx_result
 ieee80211_crypto_wep_encrypt(struct ieee80211_txrx_data *tx);
 
 #endif /* WEP_H */
diff --git a/package/mac80211/src/net/mac80211/wme.c b/package/mac80211/src/net/mac80211/wme.c
index 5b8a157975..7bbc79371d 100644
--- a/package/mac80211/src/net/mac80211/wme.c
+++ b/package/mac80211/src/net/mac80211/wme.c
@@ -19,15 +19,19 @@
 #include "wme.h"
 
 /* maximum number of hardware queues we support. */
-#define TC_80211_MAX_QUEUES 8
+#define TC_80211_MAX_QUEUES 16
+
+const int ieee802_1d_to_ac[8] = { 2, 3, 3, 2, 1, 1, 0, 0 };
 
 struct ieee80211_sched_data
 {
+	unsigned long qdisc_pool;
 	struct tcf_proto *filter_list;
 	struct Qdisc *queues[TC_80211_MAX_QUEUES];
 	struct sk_buff_head requeued[TC_80211_MAX_QUEUES];
 };
 
+static const char llc_ip_hdr[8] = {0xAA, 0xAA, 0x3, 0, 0, 0, 0x08, 0};
 
 /* given a data frame determine the 802.1p/1d tag to use */
 static inline unsigned classify_1d(struct sk_buff *skb, struct Qdisc *qd)
@@ -54,12 +58,12 @@ static inline unsigned classify_1d(struct sk_buff *skb, struct Qdisc *qd)
 		return skb->priority - 256;
 
 	/* check there is a valid IP header present */
-	offset = ieee80211_get_hdrlen_from_skb(skb) + 8 /* LLC + proto */;
-	if (skb->protocol != __constant_htons(ETH_P_IP) ||
-	    skb->len < offset + sizeof(*ip))
+	offset = ieee80211_get_hdrlen_from_skb(skb);
+	if (skb->len < offset + sizeof(llc_ip_hdr) + sizeof(*ip) ||
+	    memcmp(skb->data + offset, llc_ip_hdr, sizeof(llc_ip_hdr)))
 		return 0;
 
-	ip = (struct iphdr *) (skb->data + offset);
+	ip = (struct iphdr *) (skb->data + offset + sizeof(llc_ip_hdr));
 
 	dscp = ip->tos & 0xfc;
 	if (dscp & 0x1c)
@@ -97,7 +101,6 @@ static inline int classify80211(struct sk_buff *skb, struct Qdisc *qd)
 	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
 	unsigned short fc = le16_to_cpu(hdr->frame_control);
 	int qos;
-	const int ieee802_1d_to_ac[8] = { 2, 3, 3, 2, 1, 1, 0, 0 };
 
 	/* see if frame is data or non data frame */
 	if (unlikely((fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA)) {
@@ -145,9 +148,25 @@ static int wme_qdiscop_enqueue(struct sk_buff *skb, struct Qdisc* qd)
 	unsigned short fc = le16_to_cpu(hdr->frame_control);
 	struct Qdisc *qdisc;
 	int err, queue;
+	struct sta_info *sta;
+	u8 tid;
 
 	if (pkt_data->flags & IEEE80211_TXPD_REQUEUE) {
-		skb_queue_tail(&q->requeued[pkt_data->queue], skb);
+		queue = pkt_data->queue;
+		sta = sta_info_get(local, hdr->addr1);
+		tid = skb->priority & QOS_CONTROL_TAG1D_MASK;
+		if (sta) {
+			int ampdu_queue = sta->tid_to_tx_q[tid];
+			if ((ampdu_queue < local->hw.queues) &&
+			    test_bit(ampdu_queue, &q->qdisc_pool)) {
+				queue = ampdu_queue;
+				pkt_data->flags |= IEEE80211_TXPD_AMPDU;
+			} else {
+				pkt_data->flags &= ~IEEE80211_TXPD_AMPDU;
+			}
+			sta_info_put(sta);
+		}
+		skb_queue_tail(&q->requeued[queue], skb);
 		qd->q.qlen++;
 		return 0;
 	}
@@ -158,14 +177,28 @@ static int wme_qdiscop_enqueue(struct sk_buff *skb, struct Qdisc* qd)
 	 */
 	if (WLAN_FC_IS_QOS_DATA(fc)) {
 		u8 *p = skb->data + ieee80211_get_hdrlen(fc) - 2;
-		u8 qos_hdr = skb->priority & QOS_CONTROL_TAG1D_MASK;
+		u8 ack_policy = 0;
+		tid = skb->priority & QOS_CONTROL_TAG1D_MASK;
 		if (local->wifi_wme_noack_test)
-			qos_hdr |= QOS_CONTROL_ACK_POLICY_NOACK <<
+			ack_policy |= QOS_CONTROL_ACK_POLICY_NOACK <<
 					QOS_CONTROL_ACK_POLICY_SHIFT;
 		/* qos header is 2 bytes, second reserved */
-		*p = qos_hdr;
+		*p = ack_policy | tid;
 		p++;
 		*p = 0;
+
+		sta = sta_info_get(local, hdr->addr1);
+		if (sta) {
+			int ampdu_queue = sta->tid_to_tx_q[tid];
+			if ((ampdu_queue < local->hw.queues) &&
+				test_bit(ampdu_queue, &q->qdisc_pool)) {
+				queue = ampdu_queue;
+				pkt_data->flags |= IEEE80211_TXPD_AMPDU;
+			} else {
+				pkt_data->flags &= ~IEEE80211_TXPD_AMPDU;
+			}
+			sta_info_put(sta);
+		}
 	}
 
 	if (unlikely(queue >= local->hw.queues)) {
@@ -183,6 +216,7 @@ static int wme_qdiscop_enqueue(struct sk_buff *skb, struct Qdisc* qd)
 			kfree_skb(skb);
 			err = NET_XMIT_DROP;
 	} else {
+		tid = skb->priority & QOS_CONTROL_TAG1D_MASK;
 		pkt_data->queue = (unsigned int) queue;
 		qdisc = q->queues[queue];
 		err = qdisc->enqueue(skb, qdisc);
@@ -234,10 +268,11 @@ static struct sk_buff *wme_qdiscop_dequeue(struct Qdisc* qd)
 	/* check all the h/w queues in numeric/priority order */
 	for (queue = 0; queue < hw->queues; queue++) {
 		/* see if there is room in this hardware queue */
-		if (test_bit(IEEE80211_LINK_STATE_XOFF,
-			     &local->state[queue]) ||
-		    test_bit(IEEE80211_LINK_STATE_PENDING,
-			     &local->state[queue]))
+		if ((test_bit(IEEE80211_LINK_STATE_XOFF,
+				&local->state[queue])) ||
+		    (test_bit(IEEE80211_LINK_STATE_PENDING,
+				&local->state[queue])) ||
+			 (!test_bit(queue, &q->qdisc_pool)))
 			continue;
 
 		/* there is space - try and get a frame */
@@ -359,6 +394,10 @@ static int wme_qdiscop_init(struct Qdisc *qd, struct rtattr *opt)
 		}
 	}
 
+	/* reserve all legacy QoS queues */
+	for (i = 0; i < min(IEEE80211_TX_QUEUE_DATA4, queues); i++)
+		set_bit(i, &q->qdisc_pool);
+
 	return err;
 }
 
@@ -604,3 +643,80 @@ void ieee80211_wme_unregister(void)
 {
 	unregister_qdisc(&wme_qdisc_ops);
 }
+
+int ieee80211_ht_agg_queue_add(struct ieee80211_local *local,
+			struct sta_info *sta, u16 tid)
+{
+	int i;
+	struct ieee80211_sched_data *q =
+			qdisc_priv(local->mdev->qdisc_sleeping);
+	DECLARE_MAC_BUF(mac);
+
+	/* prepare the filter and save it for the SW queue
+	 * matching the recieved HW queue */
+
+	/* try to get a Qdisc from the pool */
+	for (i = IEEE80211_TX_QUEUE_BEACON; i < local->hw.queues; i++)
+		if (!test_and_set_bit(i, &q->qdisc_pool)) {
+			ieee80211_stop_queue(local_to_hw(local), i);
+			sta->tid_to_tx_q[tid] = i;
+
+			/* IF there are already pending packets
+			 * on this tid first we need to drain them
+			 * on the previous queue
+			 * since HT is strict in order */
+#ifdef CONFIG_MAC80211_HT_DEBUG
+			if (net_ratelimit())
+				printk(KERN_DEBUG "allocated aggregation queue"
+					" %d tid %d addr %s pool=0x%lX\n",
+					i, tid, print_mac(mac, sta->addr),
+					q->qdisc_pool);
+#endif /* CONFIG_MAC80211_HT_DEBUG */
+			return 0;
+		}
+
+	return -EAGAIN;
+}
+
+/**
+ * the caller needs to hold local->mdev->queue_lock
+ */
+void ieee80211_ht_agg_queue_remove(struct ieee80211_local *local,
+				   struct sta_info *sta, u16 tid,
+				   u8 requeue)
+{
+	struct ieee80211_sched_data *q =
+		qdisc_priv(local->mdev->qdisc_sleeping);
+	int agg_queue = sta->tid_to_tx_q[tid];
+
+	/* return the qdisc to the pool */
+	clear_bit(agg_queue, &q->qdisc_pool);
+	sta->tid_to_tx_q[tid] = local->hw.queues;
+
+	if (requeue)
+		ieee80211_requeue(local, agg_queue);
+	else
+		q->queues[agg_queue]->ops->reset(q->queues[agg_queue]);
+}
+
+void ieee80211_requeue(struct ieee80211_local *local, int queue)
+{
+	struct Qdisc *root_qd = local->mdev->qdisc_sleeping;
+	struct ieee80211_sched_data *q = qdisc_priv(root_qd);
+	struct Qdisc *qdisc = q->queues[queue];
+	struct sk_buff *skb = NULL;
+	u32 len = qdisc->q.qlen;
+
+	if (!qdisc || !qdisc->dequeue)
+		return;
+
+	printk(KERN_DEBUG "requeue: qlen = %d\n", qdisc->q.qlen);
+	for (len = qdisc->q.qlen; len > 0; len--) {
+		skb = qdisc->dequeue(qdisc);
+		root_qd->q.qlen--;
+		/* packet will be classified again and */
+		/* skb->packet_data->queue will be overridden if needed */
+		if (skb)
+			wme_qdiscop_enqueue(skb, root_qd);
+	}
+}
diff --git a/package/mac80211/src/net/mac80211/wme.h b/package/mac80211/src/net/mac80211/wme.h
index 76c713a645..fcc6b05508 100644
--- a/package/mac80211/src/net/mac80211/wme.h
+++ b/package/mac80211/src/net/mac80211/wme.h
@@ -24,6 +24,8 @@
 
 #define QOS_CONTROL_TAG1D_MASK 0x07
 
+extern const int ieee802_1d_to_ac[8];
+
 static inline int WLAN_FC_IS_QOS_DATA(u16 fc)
 {
 	return (fc & 0x8C) == 0x88;
@@ -32,7 +34,12 @@ static inline int WLAN_FC_IS_QOS_DATA(u16 fc)
 #ifdef CONFIG_NET_SCHED
 void ieee80211_install_qdisc(struct net_device *dev);
 int ieee80211_qdisc_installed(struct net_device *dev);
-
+int ieee80211_ht_agg_queue_add(struct ieee80211_local *local,
+			       struct sta_info *sta, u16 tid);
+void ieee80211_ht_agg_queue_remove(struct ieee80211_local *local,
+				   struct sta_info *sta, u16 tid,
+				   u8 requeue);
+void ieee80211_requeue(struct ieee80211_local *local, int queue);
 int ieee80211_wme_register(void);
 void ieee80211_wme_unregister(void);
 #else
@@ -43,7 +50,19 @@ static inline int ieee80211_qdisc_installed(struct net_device *dev)
 {
 	return 0;
 }
-
+static inline int ieee80211_ht_agg_queue_add(struct ieee80211_local *local,
+					     struct sta_info *sta, u16 tid)
+{
+	return -EAGAIN;
+}
+static inline void ieee80211_ht_agg_queue_remove(struct ieee80211_local *local,
+						 struct sta_info *sta, u16 tid,
+						 u8 requeue)
+{
+}
+static inline void ieee80211_requeue(struct ieee80211_local *local, int queue)
+{
+}
 static inline int ieee80211_wme_register(void)
 {
 	return 0;
diff --git a/package/mac80211/src/net/mac80211/wpa.c b/package/mac80211/src/net/mac80211/wpa.c
index 0b32ab64eb..b35e51c6ce 100644
--- a/package/mac80211/src/net/mac80211/wpa.c
+++ b/package/mac80211/src/net/mac80211/wpa.c
@@ -70,7 +70,7 @@ static int ieee80211_get_hdr_info(const struct sk_buff *skb, u8 **sa, u8 **da,
 }
 
 
-ieee80211_txrx_result
+ieee80211_tx_result
 ieee80211_tx_h_michael_mic_add(struct ieee80211_txrx_data *tx)
 {
 	u8 *data, *sa, *da, *key, *mic, qos_tid;
@@ -84,10 +84,10 @@ ieee80211_tx_h_michael_mic_add(struct ieee80211_txrx_data *tx)
 
 	if (!tx->key || tx->key->conf.alg != ALG_TKIP || skb->len < 24 ||
 	    !WLAN_FC_DATA_PRESENT(fc))
-		return TXRX_CONTINUE;
+		return TX_CONTINUE;
 
 	if (ieee80211_get_hdr_info(skb, &sa, &da, &qos_tid, &data, &data_len))
-		return TXRX_DROP;
+		return TX_DROP;
 
 	if ((tx->key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE) &&
 	    !(tx->flags & IEEE80211_TXRXD_FRAGMENTED) &&
@@ -95,7 +95,7 @@ ieee80211_tx_h_michael_mic_add(struct ieee80211_txrx_data *tx)
 	    !wpa_test) {
 		/* hwaccel - with no need for preallocated room for Michael MIC
 		 */
-		return TXRX_CONTINUE;
+		return TX_CONTINUE;
 	}
 
 	if (skb_tailroom(skb) < MICHAEL_MIC_LEN) {
@@ -105,7 +105,7 @@ ieee80211_tx_h_michael_mic_add(struct ieee80211_txrx_data *tx)
 					      GFP_ATOMIC))) {
 			printk(KERN_DEBUG "%s: failed to allocate more memory "
 			       "for Michael MIC\n", tx->dev->name);
-			return TXRX_DROP;
+			return TX_DROP;
 		}
 	}
 
@@ -119,11 +119,11 @@ ieee80211_tx_h_michael_mic_add(struct ieee80211_txrx_data *tx)
 	mic = skb_put(skb, MICHAEL_MIC_LEN);
 	michael_mic(key, da, sa, qos_tid & 0x0f, data, data_len, mic);
 
-	return TXRX_CONTINUE;
+	return TX_CONTINUE;
 }
 
 
-ieee80211_txrx_result
+ieee80211_rx_result
 ieee80211_rx_h_michael_mic_verify(struct ieee80211_txrx_data *rx)
 {
 	u8 *data, *sa, *da, *key = NULL, qos_tid;
@@ -132,6 +132,7 @@ ieee80211_rx_h_michael_mic_verify(struct ieee80211_txrx_data *rx)
 	u8 mic[MICHAEL_MIC_LEN];
 	struct sk_buff *skb = rx->skb;
 	int authenticator = 1, wpa_test = 0;
+	DECLARE_MAC_BUF(mac);
 
 	fc = rx->fc;
 
@@ -139,15 +140,15 @@ ieee80211_rx_h_michael_mic_verify(struct ieee80211_txrx_data *rx)
 	 * No way to verify the MIC if the hardware stripped it
 	 */
 	if (rx->u.rx.status->flag & RX_FLAG_MMIC_STRIPPED)
-		return TXRX_CONTINUE;
+		return RX_CONTINUE;
 
 	if (!rx->key || rx->key->conf.alg != ALG_TKIP ||
 	    !(rx->fc & IEEE80211_FCTL_PROTECTED) || !WLAN_FC_DATA_PRESENT(fc))
-		return TXRX_CONTINUE;
+		return RX_CONTINUE;
 
 	if (ieee80211_get_hdr_info(skb, &sa, &da, &qos_tid, &data, &data_len)
 	    || data_len < MICHAEL_MIC_LEN)
-		return TXRX_DROP;
+		return RX_DROP_UNUSABLE;
 
 	data_len -= MICHAEL_MIC_LEN;
 
@@ -161,14 +162,14 @@ ieee80211_rx_h_michael_mic_verify(struct ieee80211_txrx_data *rx)
 	michael_mic(key, da, sa, qos_tid & 0x0f, data, data_len, mic);
 	if (memcmp(mic, data + data_len, MICHAEL_MIC_LEN) != 0 || wpa_test) {
 		if (!(rx->flags & IEEE80211_TXRXD_RXRA_MATCH))
-			return TXRX_DROP;
+			return RX_DROP_UNUSABLE;
 
 		printk(KERN_DEBUG "%s: invalid Michael MIC in data frame from "
-		       MAC_FMT "\n", rx->dev->name, MAC_ARG(sa));
+		       "%s\n", rx->dev->name, print_mac(mac, sa));
 
 		mac80211_ev_michael_mic_failure(rx->dev, rx->key->conf.keyidx,
 						(void *) skb->data);
-		return TXRX_DROP;
+		return RX_DROP_UNUSABLE;
 	}
 
 	/* remove Michael MIC from payload */
@@ -178,7 +179,7 @@ ieee80211_rx_h_michael_mic_verify(struct ieee80211_txrx_data *rx)
 	rx->key->u.tkip.iv32_rx[rx->u.rx.queue] = rx->u.rx.tkip_iv32;
 	rx->key->u.tkip.iv16_rx[rx->u.rx.queue] = rx->u.rx.tkip_iv16;
 
-	return TXRX_CONTINUE;
+	return RX_CONTINUE;
 }
 
 
@@ -241,19 +242,12 @@ static int tkip_encrypt_skb(struct ieee80211_txrx_data *tx,
 }
 
 
-ieee80211_txrx_result
+ieee80211_tx_result
 ieee80211_crypto_tkip_encrypt(struct ieee80211_txrx_data *tx)
 {
-	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) tx->skb->data;
-	u16 fc;
 	struct sk_buff *skb = tx->skb;
 	int wpa_test = 0, test = 0;
 
-	fc = le16_to_cpu(hdr->frame_control);
-
-	if (!WLAN_FC_DATA_PRESENT(fc))
-		return TXRX_CONTINUE;
-
 	tx->u.tx.control->icv_len = TKIP_ICV_LEN;
 	tx->u.tx.control->iv_len = TKIP_IV_LEN;
 	ieee80211_tx_set_iswep(tx);
@@ -263,26 +257,26 @@ ieee80211_crypto_tkip_encrypt(struct ieee80211_txrx_data *tx)
 	    !wpa_test) {
 		/* hwaccel - with no need for preallocated room for IV/ICV */
 		tx->u.tx.control->key_idx = tx->key->conf.hw_key_idx;
-		return TXRX_CONTINUE;
+		return TX_CONTINUE;
 	}
 
 	if (tkip_encrypt_skb(tx, skb, test) < 0)
-		return TXRX_DROP;
+		return TX_DROP;
 
 	if (tx->u.tx.extra_frag) {
 		int i;
 		for (i = 0; i < tx->u.tx.num_extra_frag; i++) {
 			if (tkip_encrypt_skb(tx, tx->u.tx.extra_frag[i], test)
 			    < 0)
-				return TXRX_DROP;
+				return TX_DROP;
 		}
 	}
 
-	return TXRX_CONTINUE;
+	return TX_CONTINUE;
 }
 
 
-ieee80211_txrx_result
+ieee80211_rx_result
 ieee80211_crypto_tkip_decrypt(struct ieee80211_txrx_data *rx)
 {
 	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) rx->skb->data;
@@ -290,15 +284,16 @@ ieee80211_crypto_tkip_decrypt(struct ieee80211_txrx_data *rx)
 	int hdrlen, res, hwaccel = 0, wpa_test = 0;
 	struct ieee80211_key *key = rx->key;
 	struct sk_buff *skb = rx->skb;
+	DECLARE_MAC_BUF(mac);
 
 	fc = le16_to_cpu(hdr->frame_control);
 	hdrlen = ieee80211_get_hdrlen(fc);
 
 	if ((rx->fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA)
-		return TXRX_CONTINUE;
+		return RX_CONTINUE;
 
 	if (!rx->sta || skb->len - hdrlen < 12)
-		return TXRX_DROP;
+		return RX_DROP_UNUSABLE;
 
 	if (rx->u.rx.status->flag & RX_FLAG_DECRYPTED) {
 		if (rx->u.rx.status->flag & RX_FLAG_IV_STRIPPED) {
@@ -307,7 +302,7 @@ ieee80211_crypto_tkip_decrypt(struct ieee80211_txrx_data *rx)
 			 * replay protection, and stripped the ICV/IV so
 			 * we cannot do any checks here.
 			 */
-			return TXRX_CONTINUE;
+			return RX_CONTINUE;
 		}
 
 		/* let TKIP code verify IV, but skip decryption */
@@ -321,10 +316,13 @@ ieee80211_crypto_tkip_decrypt(struct ieee80211_txrx_data *rx)
 					  &rx->u.rx.tkip_iv32,
 					  &rx->u.rx.tkip_iv16);
 	if (res != TKIP_DECRYPT_OK || wpa_test) {
-		printk(KERN_DEBUG "%s: TKIP decrypt failed for RX frame from "
-		       MAC_FMT " (res=%d)\n",
-		       rx->dev->name, MAC_ARG(rx->sta->addr), res);
-		return TXRX_DROP;
+#ifdef CONFIG_MAC80211_DEBUG
+		if (net_ratelimit())
+			printk(KERN_DEBUG "%s: TKIP decrypt failed for RX "
+			       "frame from %s (res=%d)\n", rx->dev->name,
+			       print_mac(mac, rx->sta->addr), res);
+#endif /* CONFIG_MAC80211_DEBUG */
+		return RX_DROP_UNUSABLE;
 	}
 
 	/* Trim ICV */
@@ -334,7 +332,7 @@ ieee80211_crypto_tkip_decrypt(struct ieee80211_txrx_data *rx)
 	memmove(skb->data + TKIP_IV_LEN, skb->data, hdrlen);
 	skb_pull(skb, TKIP_IV_LEN);
 
-	return TXRX_CONTINUE;
+	return RX_CONTINUE;
 }
 
 
@@ -493,19 +491,12 @@ static int ccmp_encrypt_skb(struct ieee80211_txrx_data *tx,
 }
 
 
-ieee80211_txrx_result
+ieee80211_tx_result
 ieee80211_crypto_ccmp_encrypt(struct ieee80211_txrx_data *tx)
 {
-	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) tx->skb->data;
-	u16 fc;
 	struct sk_buff *skb = tx->skb;
 	int test = 0;
 
-	fc = le16_to_cpu(hdr->frame_control);
-
-	if (!WLAN_FC_DATA_PRESENT(fc))
-		return TXRX_CONTINUE;
-
 	tx->u.tx.control->icv_len = CCMP_MIC_LEN;
 	tx->u.tx.control->iv_len = CCMP_HDR_LEN;
 	ieee80211_tx_set_iswep(tx);
@@ -515,26 +506,26 @@ ieee80211_crypto_ccmp_encrypt(struct ieee80211_txrx_data *tx)
 		/* hwaccel - with no need for preallocated room for CCMP "
 		 * header or MIC fields */
 		tx->u.tx.control->key_idx = tx->key->conf.hw_key_idx;
-		return TXRX_CONTINUE;
+		return TX_CONTINUE;
 	}
 
 	if (ccmp_encrypt_skb(tx, skb, test) < 0)
-		return TXRX_DROP;
+		return TX_DROP;
 
 	if (tx->u.tx.extra_frag) {
 		int i;
 		for (i = 0; i < tx->u.tx.num_extra_frag; i++) {
 			if (ccmp_encrypt_skb(tx, tx->u.tx.extra_frag[i], test)
 			    < 0)
-				return TXRX_DROP;
+				return TX_DROP;
 		}
 	}
 
-	return TXRX_CONTINUE;
+	return TX_CONTINUE;
 }
 
 
-ieee80211_txrx_result
+ieee80211_rx_result
 ieee80211_crypto_ccmp_decrypt(struct ieee80211_txrx_data *rx)
 {
 	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) rx->skb->data;
@@ -544,35 +535,37 @@ ieee80211_crypto_ccmp_decrypt(struct ieee80211_txrx_data *rx)
 	struct sk_buff *skb = rx->skb;
 	u8 pn[CCMP_PN_LEN];
 	int data_len;
+	DECLARE_MAC_BUF(mac);
 
 	fc = le16_to_cpu(hdr->frame_control);
 	hdrlen = ieee80211_get_hdrlen(fc);
 
 	if ((rx->fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA)
-		return TXRX_CONTINUE;
+		return RX_CONTINUE;
 
 	data_len = skb->len - hdrlen - CCMP_HDR_LEN - CCMP_MIC_LEN;
 	if (!rx->sta || data_len < 0)
-		return TXRX_DROP;
+		return RX_DROP_UNUSABLE;
 
 	if ((rx->u.rx.status->flag & RX_FLAG_DECRYPTED) &&
 	    (rx->u.rx.status->flag & RX_FLAG_IV_STRIPPED))
-		return TXRX_CONTINUE;
+		return RX_CONTINUE;
 
 	(void) ccmp_hdr2pn(pn, skb->data + hdrlen);
 
 	if (memcmp(pn, key->u.ccmp.rx_pn[rx->u.rx.queue], CCMP_PN_LEN) <= 0) {
 #ifdef CONFIG_MAC80211_DEBUG
 		u8 *ppn = key->u.ccmp.rx_pn[rx->u.rx.queue];
+
 		printk(KERN_DEBUG "%s: CCMP replay detected for RX frame from "
-		       MAC_FMT " (RX PN %02x%02x%02x%02x%02x%02x <= prev. PN "
+		       "%s (RX PN %02x%02x%02x%02x%02x%02x <= prev. PN "
 		       "%02x%02x%02x%02x%02x%02x)\n", rx->dev->name,
-		       MAC_ARG(rx->sta->addr),
+		       print_mac(mac, rx->sta->addr),
 		       pn[0], pn[1], pn[2], pn[3], pn[4], pn[5],
 		       ppn[0], ppn[1], ppn[2], ppn[3], ppn[4], ppn[5]);
 #endif /* CONFIG_MAC80211_DEBUG */
 		key->u.ccmp.replays++;
-		return TXRX_DROP;
+		return RX_DROP_UNUSABLE;
 	}
 
 	if (!(rx->u.rx.status->flag & RX_FLAG_DECRYPTED)) {
@@ -590,10 +583,13 @@ ieee80211_crypto_ccmp_decrypt(struct ieee80211_txrx_data *rx)
 			    skb->data + hdrlen + CCMP_HDR_LEN, data_len,
 			    skb->data + skb->len - CCMP_MIC_LEN,
 			    skb->data + hdrlen + CCMP_HDR_LEN)) {
-			printk(KERN_DEBUG "%s: CCMP decrypt failed for RX "
-			       "frame from " MAC_FMT "\n", rx->dev->name,
-			       MAC_ARG(rx->sta->addr));
-			return TXRX_DROP;
+#ifdef CONFIG_MAC80211_DEBUG
+			if (net_ratelimit())
+				printk(KERN_DEBUG "%s: CCMP decrypt failed "
+				       "for RX frame from %s\n", rx->dev->name,
+				       print_mac(mac, rx->sta->addr));
+#endif /* CONFIG_MAC80211_DEBUG */
+			return RX_DROP_UNUSABLE;
 		}
 	}
 
@@ -604,6 +600,5 @@ ieee80211_crypto_ccmp_decrypt(struct ieee80211_txrx_data *rx)
 	memmove(skb->data + CCMP_HDR_LEN, skb->data, hdrlen);
 	skb_pull(skb, CCMP_HDR_LEN);
 
-	return TXRX_CONTINUE;
+	return RX_CONTINUE;
 }
-
diff --git a/package/mac80211/src/net/mac80211/wpa.h b/package/mac80211/src/net/mac80211/wpa.h
index 49d80cf0cd..16e4dba4aa 100644
--- a/package/mac80211/src/net/mac80211/wpa.h
+++ b/package/mac80211/src/net/mac80211/wpa.h
@@ -13,19 +13,19 @@
 #include <linux/types.h>
 #include "ieee80211_i.h"
 
-ieee80211_txrx_result
+ieee80211_tx_result
 ieee80211_tx_h_michael_mic_add(struct ieee80211_txrx_data *tx);
-ieee80211_txrx_result
+ieee80211_rx_result
 ieee80211_rx_h_michael_mic_verify(struct ieee80211_txrx_data *rx);
 
-ieee80211_txrx_result
+ieee80211_tx_result
 ieee80211_crypto_tkip_encrypt(struct ieee80211_txrx_data *tx);
-ieee80211_txrx_result
+ieee80211_rx_result
 ieee80211_crypto_tkip_decrypt(struct ieee80211_txrx_data *rx);
 
-ieee80211_txrx_result
+ieee80211_tx_result
 ieee80211_crypto_ccmp_encrypt(struct ieee80211_txrx_data *tx);
-ieee80211_txrx_result
+ieee80211_rx_result
 ieee80211_crypto_ccmp_decrypt(struct ieee80211_txrx_data *rx);
 
 #endif /* WPA_H */
diff --git a/package/mac80211/src/net/wireless/Kconfig b/package/mac80211/src/net/wireless/Kconfig
index 6291f13bba..79270903bd 100644
--- a/package/mac80211/src/net/wireless/Kconfig
+++ b/package/mac80211/src/net/wireless/Kconfig
@@ -3,16 +3,16 @@ config CFG80211
 
 config NL80211
 	bool "nl80211 new netlink interface support"
-	depends CFG80211
+	depends on CFG80211
 	default y
 	---help---
-         This option turns on the new netlink interface
-         (nl80211) support in cfg80211.
+	  This option turns on the new netlink interface
+	  (nl80211) support in cfg80211.
 
-         If =n, drivers using mac80211 will be configured via
-         wireless extension support provided by that subsystem.
+	  If =n, drivers using mac80211 will be configured via
+	  wireless extension support provided by that subsystem.
 
-         If unsure, say Y.
+	  If unsure, say Y.
 
 config WIRELESS_EXT
 	bool "Wireless extensions"
diff --git a/package/mac80211/src/net/wireless/Makefile b/package/mac80211/src/net/wireless/Makefile
index 5664c2cfd7..b9f943c45f 100644
--- a/package/mac80211/src/net/wireless/Makefile
+++ b/package/mac80211/src/net/wireless/Makefile
@@ -1,4 +1,5 @@
+obj-$(CONFIG_WIRELESS_EXT) += wext.o
 obj-$(CONFIG_CFG80211) += cfg80211.o
 
-cfg80211-y += core.o sysfs.o radiotap.o
+cfg80211-y += core.o sysfs.o radiotap.o util.o reg.o
 cfg80211-$(CONFIG_NL80211) += nl80211.o
diff --git a/package/mac80211/src/net/wireless/core.c b/package/mac80211/src/net/wireless/core.c
index 35b79bee3a..80afacdae4 100644
--- a/package/mac80211/src/net/wireless/core.c
+++ b/package/mac80211/src/net/wireless/core.c
@@ -69,7 +69,7 @@ __cfg80211_drv_from_info(struct genl_info *info)
 
 	if (info->attrs[NL80211_ATTR_IFINDEX]) {
 		ifindex = nla_get_u32(info->attrs[NL80211_ATTR_IFINDEX]);
-		dev = dev_get_by_index(ifindex);
+		dev = dev_get_by_index(&init_net, ifindex);
 		if (dev) {
 			if (dev->ieee80211_ptr)
 				byifidx =
@@ -120,7 +120,7 @@ cfg80211_get_dev_from_ifindex(int ifindex)
 	struct net_device *dev;
 
 	mutex_lock(&cfg80211_drv_mutex);
-	dev = dev_get_by_index(ifindex);
+	dev = dev_get_by_index(&init_net, ifindex);
 	if (!dev)
 		goto out;
 	if (dev->ieee80211_ptr) {
@@ -184,6 +184,9 @@ struct wiphy *wiphy_new(struct cfg80211_ops *ops, int sizeof_priv)
 	struct cfg80211_registered_device *drv;
 	int alloc_size;
 
+	WARN_ON(!ops->add_key && ops->del_key);
+	WARN_ON(ops->add_key && !ops->del_key);
+
 	alloc_size = sizeof(*drv) + sizeof_priv;
 
 	drv = kzalloc(alloc_size, GFP_KERNEL);
@@ -229,6 +232,47 @@ int wiphy_register(struct wiphy *wiphy)
 {
 	struct cfg80211_registered_device *drv = wiphy_to_dev(wiphy);
 	int res;
+	enum ieee80211_band band;
+	struct ieee80211_supported_band *sband;
+	bool have_band = false;
+	int i;
+
+	/* sanity check supported bands/channels */
+	for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
+		sband = wiphy->bands[band];
+		if (!sband)
+			continue;
+
+		sband->band = band;
+
+		if (!sband->n_channels || !sband->n_bitrates) {
+			WARN_ON(1);
+			return -EINVAL;
+		}
+
+		for (i = 0; i < sband->n_channels; i++) {
+			sband->channels[i].orig_flags =
+				sband->channels[i].flags;
+			sband->channels[i].orig_mag =
+				sband->channels[i].max_antenna_gain;
+			sband->channels[i].orig_mpwr =
+				sband->channels[i].max_power;
+			sband->channels[i].band = band;
+		}
+
+		have_band = true;
+	}
+
+	if (!have_band) {
+		WARN_ON(1);
+		return -EINVAL;
+	}
+
+	/* check and set up bitrates */
+	ieee80211_set_bitrate_flags(wiphy);
+
+	/* set up regulatory info */
+	wiphy_update_regulatory(wiphy);
 
 	mutex_lock(&cfg80211_drv_mutex);
 
diff --git a/package/mac80211/src/net/wireless/core.h b/package/mac80211/src/net/wireless/core.h
index eb0f846b40..7a02c356d6 100644
--- a/package/mac80211/src/net/wireless/core.h
+++ b/package/mac80211/src/net/wireless/core.h
@@ -78,4 +78,7 @@ extern void cfg80211_dev_free(struct cfg80211_registered_device *drv);
 extern int cfg80211_dev_rename(struct cfg80211_registered_device *drv,
 			       char *newname);
 
+void ieee80211_set_bitrate_flags(struct wiphy *wiphy);
+void wiphy_update_regulatory(struct wiphy *wiphy);
+
 #endif /* __NET_WIRELESS_CORE_H */
diff --git a/package/mac80211/src/net/wireless/nl80211.c b/package/mac80211/src/net/wireless/nl80211.c
index 58717f3037..5b3474798b 100644
--- a/package/mac80211/src/net/wireless/nl80211.c
+++ b/package/mac80211/src/net/wireless/nl80211.c
@@ -39,7 +39,7 @@ static int get_drv_dev_by_info_ifindex(struct genl_info *info,
 		return -EINVAL;
 
 	ifindex = nla_get_u32(info->attrs[NL80211_ATTR_IFINDEX]);
-	*dev = dev_get_by_index(ifindex);
+	*dev = dev_get_by_index(&init_net, ifindex);
 	if (!*dev)
 		return -ENODEV;
 
@@ -61,6 +61,28 @@ static struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] __read_mostly = {
 	[NL80211_ATTR_IFTYPE] = { .type = NLA_U32 },
 	[NL80211_ATTR_IFINDEX] = { .type = NLA_U32 },
 	[NL80211_ATTR_IFNAME] = { .type = NLA_NUL_STRING, .len = IFNAMSIZ-1 },
+
+	[NL80211_ATTR_MAC] = { .type = NLA_BINARY, .len = ETH_ALEN },
+
+	[NL80211_ATTR_KEY_DATA] = { .type = NLA_BINARY,
+				    .len = WLAN_MAX_KEY_LEN },
+	[NL80211_ATTR_KEY_IDX] = { .type = NLA_U8 },
+	[NL80211_ATTR_KEY_CIPHER] = { .type = NLA_U32 },
+	[NL80211_ATTR_KEY_DEFAULT] = { .type = NLA_FLAG },
+
+	[NL80211_ATTR_BEACON_INTERVAL] = { .type = NLA_U32 },
+	[NL80211_ATTR_DTIM_PERIOD] = { .type = NLA_U32 },
+	[NL80211_ATTR_BEACON_HEAD] = { .type = NLA_BINARY,
+				       .len = IEEE80211_MAX_DATA_LEN },
+	[NL80211_ATTR_BEACON_TAIL] = { .type = NLA_BINARY,
+				       .len = IEEE80211_MAX_DATA_LEN },
+	[NL80211_ATTR_STA_AID] = { .type = NLA_U16 },
+	[NL80211_ATTR_STA_FLAGS] = { .type = NLA_NESTED },
+	[NL80211_ATTR_STA_LISTEN_INTERVAL] = { .type = NLA_U16 },
+	[NL80211_ATTR_STA_SUPPORTED_RATES] = { .type = NLA_BINARY,
+					       .len = NL80211_MAX_SUPP_RATES },
+	[NL80211_ATTR_STA_VLAN] = { .type = NLA_U32 },
+	[NL80211_ATTR_MNTR_FLAGS] = { .type = NLA_NESTED },
 };
 
 /* message building helper */
@@ -77,6 +99,13 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags,
 			      struct cfg80211_registered_device *dev)
 {
 	void *hdr;
+	struct nlattr *nl_bands, *nl_band;
+	struct nlattr *nl_freqs, *nl_freq;
+	struct nlattr *nl_rates, *nl_rate;
+	enum ieee80211_band band;
+	struct ieee80211_channel *chan;
+	struct ieee80211_rate *rate;
+	int i;
 
 	hdr = nl80211hdr_put(msg, pid, seq, flags, NL80211_CMD_NEW_WIPHY);
 	if (!hdr)
@@ -84,6 +113,73 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags,
 
 	NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, dev->idx);
 	NLA_PUT_STRING(msg, NL80211_ATTR_WIPHY_NAME, wiphy_name(&dev->wiphy));
+
+	nl_bands = nla_nest_start(msg, NL80211_ATTR_WIPHY_BANDS);
+	if (!nl_bands)
+		goto nla_put_failure;
+
+	for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
+		if (!dev->wiphy.bands[band])
+			continue;
+
+		nl_band = nla_nest_start(msg, band);
+		if (!nl_band)
+			goto nla_put_failure;
+
+		/* add frequencies */
+		nl_freqs = nla_nest_start(msg, NL80211_BAND_ATTR_FREQS);
+		if (!nl_freqs)
+			goto nla_put_failure;
+
+		for (i = 0; i < dev->wiphy.bands[band]->n_channels; i++) {
+			nl_freq = nla_nest_start(msg, i);
+			if (!nl_freq)
+				goto nla_put_failure;
+
+			chan = &dev->wiphy.bands[band]->channels[i];
+			NLA_PUT_U32(msg, NL80211_FREQUENCY_ATTR_FREQ,
+				    chan->center_freq);
+
+			if (chan->flags & IEEE80211_CHAN_DISABLED)
+				NLA_PUT_FLAG(msg, NL80211_FREQUENCY_ATTR_DISABLED);
+			if (chan->flags & IEEE80211_CHAN_PASSIVE_SCAN)
+				NLA_PUT_FLAG(msg, NL80211_FREQUENCY_ATTR_PASSIVE_SCAN);
+			if (chan->flags & IEEE80211_CHAN_NO_IBSS)
+				NLA_PUT_FLAG(msg, NL80211_FREQUENCY_ATTR_NO_IBSS);
+			if (chan->flags & IEEE80211_CHAN_RADAR)
+				NLA_PUT_FLAG(msg, NL80211_FREQUENCY_ATTR_RADAR);
+
+			nla_nest_end(msg, nl_freq);
+		}
+
+		nla_nest_end(msg, nl_freqs);
+
+		/* add bitrates */
+		nl_rates = nla_nest_start(msg, NL80211_BAND_ATTR_RATES);
+		if (!nl_rates)
+			goto nla_put_failure;
+
+		for (i = 0; i < dev->wiphy.bands[band]->n_bitrates; i++) {
+			nl_rate = nla_nest_start(msg, i);
+			if (!nl_rate)
+				goto nla_put_failure;
+
+			rate = &dev->wiphy.bands[band]->bitrates[i];
+			NLA_PUT_U32(msg, NL80211_BITRATE_ATTR_RATE,
+				    rate->bitrate);
+			if (rate->flags & IEEE80211_RATE_SHORT_PREAMBLE)
+				NLA_PUT_FLAG(msg,
+					NL80211_BITRATE_ATTR_2GHZ_SHORTPREAMBLE);
+
+			nla_nest_end(msg, nl_rate);
+		}
+
+		nla_nest_end(msg, nl_rates);
+
+		nla_nest_end(msg, nl_band);
+	}
+	nla_nest_end(msg, nl_bands);
+
 	return genlmsg_end(msg, hdr);
 
  nla_put_failure:
@@ -241,12 +337,42 @@ static int nl80211_get_interface(struct sk_buff *skb, struct genl_info *info)
 	return -ENOBUFS;
 }
 
+static const struct nla_policy mntr_flags_policy[NL80211_MNTR_FLAG_MAX + 1] = {
+	[NL80211_MNTR_FLAG_FCSFAIL] = { .type = NLA_FLAG },
+	[NL80211_MNTR_FLAG_PLCPFAIL] = { .type = NLA_FLAG },
+	[NL80211_MNTR_FLAG_CONTROL] = { .type = NLA_FLAG },
+	[NL80211_MNTR_FLAG_OTHER_BSS] = { .type = NLA_FLAG },
+	[NL80211_MNTR_FLAG_COOK_FRAMES] = { .type = NLA_FLAG },
+};
+
+static int parse_monitor_flags(struct nlattr *nla, u32 *mntrflags)
+{
+	struct nlattr *flags[NL80211_MNTR_FLAG_MAX + 1];
+	int flag;
+
+	*mntrflags = 0;
+
+	if (!nla)
+		return -EINVAL;
+
+	if (nla_parse_nested(flags, NL80211_MNTR_FLAG_MAX,
+			     nla, mntr_flags_policy))
+		return -EINVAL;
+
+	for (flag = 1; flag <= NL80211_MNTR_FLAG_MAX; flag++)
+		if (flags[flag])
+			*mntrflags |= (1<<flag);
+
+	return 0;
+}
+
 static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info)
 {
 	struct cfg80211_registered_device *drv;
 	int err, ifindex;
 	enum nl80211_iftype type;
 	struct net_device *dev;
+	u32 flags;
 
 	if (info->attrs[NL80211_ATTR_IFTYPE]) {
 		type = nla_get_u32(info->attrs[NL80211_ATTR_IFTYPE]);
@@ -267,7 +393,11 @@ static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info)
 	}
 
 	rtnl_lock();
-	err = drv->ops->change_virtual_intf(&drv->wiphy, ifindex, type);
+	err = parse_monitor_flags(type == NL80211_IFTYPE_MONITOR ?
+				  info->attrs[NL80211_ATTR_MNTR_FLAGS] : NULL,
+				  &flags);
+	err = drv->ops->change_virtual_intf(&drv->wiphy, ifindex,
+					    type, err ? NULL : &flags);
 	rtnl_unlock();
 
  unlock:
@@ -280,6 +410,7 @@ static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info)
 	struct cfg80211_registered_device *drv;
 	int err;
 	enum nl80211_iftype type = NL80211_IFTYPE_UNSPECIFIED;
+	u32 flags;
 
 	if (!info->attrs[NL80211_ATTR_IFNAME])
 		return -EINVAL;
@@ -300,8 +431,12 @@ static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info)
 	}
 
 	rtnl_lock();
+	err = parse_monitor_flags(type == NL80211_IFTYPE_MONITOR ?
+				  info->attrs[NL80211_ATTR_MNTR_FLAGS] : NULL,
+				  &flags);
 	err = drv->ops->add_virtual_intf(&drv->wiphy,
-		nla_data(info->attrs[NL80211_ATTR_IFNAME]), type);
+		nla_data(info->attrs[NL80211_ATTR_IFNAME]),
+		type, err ? NULL : &flags);
 	rtnl_unlock();
 
  unlock:
@@ -335,6 +470,655 @@ static int nl80211_del_interface(struct sk_buff *skb, struct genl_info *info)
 	return err;
 }
 
+struct get_key_cookie {
+	struct sk_buff *msg;
+	int error;
+};
+
+static void get_key_callback(void *c, struct key_params *params)
+{
+	struct get_key_cookie *cookie = c;
+
+	if (params->key)
+		NLA_PUT(cookie->msg, NL80211_ATTR_KEY_DATA,
+			params->key_len, params->key);
+
+	if (params->seq)
+		NLA_PUT(cookie->msg, NL80211_ATTR_KEY_SEQ,
+			params->seq_len, params->seq);
+
+	if (params->cipher)
+		NLA_PUT_U32(cookie->msg, NL80211_ATTR_KEY_CIPHER,
+			    params->cipher);
+
+	return;
+ nla_put_failure:
+	cookie->error = 1;
+}
+
+static int nl80211_get_key(struct sk_buff *skb, struct genl_info *info)
+{
+	struct cfg80211_registered_device *drv;
+	int err;
+	struct net_device *dev;
+	u8 key_idx = 0;
+	u8 *mac_addr = NULL;
+	struct get_key_cookie cookie = {
+		.error = 0,
+	};
+	void *hdr;
+	struct sk_buff *msg;
+
+	if (info->attrs[NL80211_ATTR_KEY_IDX])
+		key_idx = nla_get_u8(info->attrs[NL80211_ATTR_KEY_IDX]);
+
+	if (key_idx > 3)
+		return -EINVAL;
+
+	if (info->attrs[NL80211_ATTR_MAC])
+		mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
+
+	err = get_drv_dev_by_info_ifindex(info, &drv, &dev);
+	if (err)
+		return err;
+
+	if (!drv->ops->get_key) {
+		err = -EOPNOTSUPP;
+		goto out;
+	}
+
+	msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
+	if (!msg) {
+		err = -ENOMEM;
+		goto out;
+	}
+
+	hdr = nl80211hdr_put(msg, info->snd_pid, info->snd_seq, 0,
+			     NL80211_CMD_NEW_KEY);
+
+	if (IS_ERR(hdr)) {
+		err = PTR_ERR(hdr);
+		goto out;
+	}
+
+	cookie.msg = msg;
+
+	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, dev->ifindex);
+	NLA_PUT_U8(msg, NL80211_ATTR_KEY_IDX, key_idx);
+	if (mac_addr)
+		NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, mac_addr);
+
+	rtnl_lock();
+	err = drv->ops->get_key(&drv->wiphy, dev, key_idx, mac_addr,
+				&cookie, get_key_callback);
+	rtnl_unlock();
+
+	if (err)
+		goto out;
+
+	if (cookie.error)
+		goto nla_put_failure;
+
+	genlmsg_end(msg, hdr);
+	err = genlmsg_unicast(msg, info->snd_pid);
+	goto out;
+
+ nla_put_failure:
+	err = -ENOBUFS;
+	nlmsg_free(msg);
+ out:
+	cfg80211_put_dev(drv);
+	dev_put(dev);
+	return err;
+}
+
+static int nl80211_set_key(struct sk_buff *skb, struct genl_info *info)
+{
+	struct cfg80211_registered_device *drv;
+	int err;
+	struct net_device *dev;
+	u8 key_idx;
+
+	if (!info->attrs[NL80211_ATTR_KEY_IDX])
+		return -EINVAL;
+
+	key_idx = nla_get_u8(info->attrs[NL80211_ATTR_KEY_IDX]);
+
+	if (key_idx > 3)
+		return -EINVAL;
+
+	/* currently only support setting default key */
+	if (!info->attrs[NL80211_ATTR_KEY_DEFAULT])
+		return -EINVAL;
+
+	err = get_drv_dev_by_info_ifindex(info, &drv, &dev);
+	if (err)
+		return err;
+
+	if (!drv->ops->set_default_key) {
+		err = -EOPNOTSUPP;
+		goto out;
+	}
+
+	rtnl_lock();
+	err = drv->ops->set_default_key(&drv->wiphy, dev, key_idx);
+	rtnl_unlock();
+
+ out:
+	cfg80211_put_dev(drv);
+	dev_put(dev);
+	return err;
+}
+
+static int nl80211_new_key(struct sk_buff *skb, struct genl_info *info)
+{
+	struct cfg80211_registered_device *drv;
+	int err;
+	struct net_device *dev;
+	struct key_params params;
+	u8 key_idx = 0;
+	u8 *mac_addr = NULL;
+
+	memset(&params, 0, sizeof(params));
+
+	if (!info->attrs[NL80211_ATTR_KEY_CIPHER])
+		return -EINVAL;
+
+	if (info->attrs[NL80211_ATTR_KEY_DATA]) {
+		params.key = nla_data(info->attrs[NL80211_ATTR_KEY_DATA]);
+		params.key_len = nla_len(info->attrs[NL80211_ATTR_KEY_DATA]);
+	}
+
+	if (info->attrs[NL80211_ATTR_KEY_IDX])
+		key_idx = nla_get_u8(info->attrs[NL80211_ATTR_KEY_IDX]);
+
+	params.cipher = nla_get_u32(info->attrs[NL80211_ATTR_KEY_CIPHER]);
+
+	if (info->attrs[NL80211_ATTR_MAC])
+		mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
+
+	if (key_idx > 3)
+		return -EINVAL;
+
+	/*
+	 * Disallow pairwise keys with non-zero index unless it's WEP
+	 * (because current deployments use pairwise WEP keys with
+	 * non-zero indizes but 802.11i clearly specifies to use zero)
+	 */
+	if (mac_addr && key_idx &&
+	    params.cipher != WLAN_CIPHER_SUITE_WEP40 &&
+	    params.cipher != WLAN_CIPHER_SUITE_WEP104)
+		return -EINVAL;
+
+	/* TODO: add definitions for the lengths to linux/ieee80211.h */
+	switch (params.cipher) {
+	case WLAN_CIPHER_SUITE_WEP40:
+		if (params.key_len != 5)
+			return -EINVAL;
+		break;
+	case WLAN_CIPHER_SUITE_TKIP:
+		if (params.key_len != 32)
+			return -EINVAL;
+		break;
+	case WLAN_CIPHER_SUITE_CCMP:
+		if (params.key_len != 16)
+			return -EINVAL;
+		break;
+	case WLAN_CIPHER_SUITE_WEP104:
+		if (params.key_len != 13)
+			return -EINVAL;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	err = get_drv_dev_by_info_ifindex(info, &drv, &dev);
+	if (err)
+		return err;
+
+	if (!drv->ops->add_key) {
+		err = -EOPNOTSUPP;
+		goto out;
+	}
+
+	rtnl_lock();
+	err = drv->ops->add_key(&drv->wiphy, dev, key_idx, mac_addr, &params);
+	rtnl_unlock();
+
+ out:
+	cfg80211_put_dev(drv);
+	dev_put(dev);
+	return err;
+}
+
+static int nl80211_del_key(struct sk_buff *skb, struct genl_info *info)
+{
+	struct cfg80211_registered_device *drv;
+	int err;
+	struct net_device *dev;
+	u8 key_idx = 0;
+	u8 *mac_addr = NULL;
+
+	if (info->attrs[NL80211_ATTR_KEY_IDX])
+		key_idx = nla_get_u8(info->attrs[NL80211_ATTR_KEY_IDX]);
+
+	if (key_idx > 3)
+		return -EINVAL;
+
+	if (info->attrs[NL80211_ATTR_MAC])
+		mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
+
+	err = get_drv_dev_by_info_ifindex(info, &drv, &dev);
+	if (err)
+		return err;
+
+	if (!drv->ops->del_key) {
+		err = -EOPNOTSUPP;
+		goto out;
+	}
+
+	rtnl_lock();
+	err = drv->ops->del_key(&drv->wiphy, dev, key_idx, mac_addr);
+	rtnl_unlock();
+
+ out:
+	cfg80211_put_dev(drv);
+	dev_put(dev);
+	return err;
+}
+
+static int nl80211_addset_beacon(struct sk_buff *skb, struct genl_info *info)
+{
+        int (*call)(struct wiphy *wiphy, struct net_device *dev,
+		    struct beacon_parameters *info);
+	struct cfg80211_registered_device *drv;
+	int err;
+	struct net_device *dev;
+	struct beacon_parameters params;
+	int haveinfo = 0;
+
+	err = get_drv_dev_by_info_ifindex(info, &drv, &dev);
+	if (err)
+		return err;
+
+	switch (info->genlhdr->cmd) {
+	case NL80211_CMD_NEW_BEACON:
+		/* these are required for NEW_BEACON */
+		if (!info->attrs[NL80211_ATTR_BEACON_INTERVAL] ||
+		    !info->attrs[NL80211_ATTR_DTIM_PERIOD] ||
+		    !info->attrs[NL80211_ATTR_BEACON_HEAD]) {
+			err = -EINVAL;
+			goto out;
+		}
+
+		call = drv->ops->add_beacon;
+		break;
+	case NL80211_CMD_SET_BEACON:
+		call = drv->ops->set_beacon;
+		break;
+	default:
+		WARN_ON(1);
+		err = -EOPNOTSUPP;
+		goto out;
+	}
+
+	if (!call) {
+		err = -EOPNOTSUPP;
+		goto out;
+	}
+
+	memset(&params, 0, sizeof(params));
+
+	if (info->attrs[NL80211_ATTR_BEACON_INTERVAL]) {
+		params.interval =
+		    nla_get_u32(info->attrs[NL80211_ATTR_BEACON_INTERVAL]);
+		haveinfo = 1;
+	}
+
+	if (info->attrs[NL80211_ATTR_DTIM_PERIOD]) {
+		params.dtim_period =
+		    nla_get_u32(info->attrs[NL80211_ATTR_DTIM_PERIOD]);
+		haveinfo = 1;
+	}
+
+	if (info->attrs[NL80211_ATTR_BEACON_HEAD]) {
+		params.head = nla_data(info->attrs[NL80211_ATTR_BEACON_HEAD]);
+		params.head_len =
+		    nla_len(info->attrs[NL80211_ATTR_BEACON_HEAD]);
+		haveinfo = 1;
+	}
+
+	if (info->attrs[NL80211_ATTR_BEACON_TAIL]) {
+		params.tail = nla_data(info->attrs[NL80211_ATTR_BEACON_TAIL]);
+		params.tail_len =
+		    nla_len(info->attrs[NL80211_ATTR_BEACON_TAIL]);
+		haveinfo = 1;
+	}
+
+	if (!haveinfo) {
+		err = -EINVAL;
+		goto out;
+	}
+
+	rtnl_lock();
+	err = call(&drv->wiphy, dev, &params);
+	rtnl_unlock();
+
+ out:
+	cfg80211_put_dev(drv);
+	dev_put(dev);
+	return err;
+}
+
+static int nl80211_del_beacon(struct sk_buff *skb, struct genl_info *info)
+{
+	struct cfg80211_registered_device *drv;
+	int err;
+	struct net_device *dev;
+
+	err = get_drv_dev_by_info_ifindex(info, &drv, &dev);
+	if (err)
+		return err;
+
+	if (!drv->ops->del_beacon) {
+		err = -EOPNOTSUPP;
+		goto out;
+	}
+
+	rtnl_lock();
+	err = drv->ops->del_beacon(&drv->wiphy, dev);
+	rtnl_unlock();
+
+ out:
+	cfg80211_put_dev(drv);
+	dev_put(dev);
+	return err;
+}
+
+static const struct nla_policy sta_flags_policy[NL80211_STA_FLAG_MAX + 1] = {
+	[NL80211_STA_FLAG_AUTHORIZED] = { .type = NLA_FLAG },
+	[NL80211_STA_FLAG_SHORT_PREAMBLE] = { .type = NLA_FLAG },
+	[NL80211_STA_FLAG_WME] = { .type = NLA_FLAG },
+};
+
+static int parse_station_flags(struct nlattr *nla, u32 *staflags)
+{
+	struct nlattr *flags[NL80211_STA_FLAG_MAX + 1];
+	int flag;
+
+	*staflags = 0;
+
+	if (!nla)
+		return 0;
+
+	if (nla_parse_nested(flags, NL80211_STA_FLAG_MAX,
+			     nla, sta_flags_policy))
+		return -EINVAL;
+
+	*staflags = STATION_FLAG_CHANGED;
+
+	for (flag = 1; flag <= NL80211_STA_FLAG_MAX; flag++)
+		if (flags[flag])
+			*staflags |= (1<<flag);
+
+	return 0;
+}
+
+static int nl80211_send_station(struct sk_buff *msg, u32 pid, u32 seq,
+				int flags, struct net_device *dev,
+				u8 *mac_addr, struct station_stats *stats)
+{
+	void *hdr;
+	struct nlattr *statsattr;
+
+	hdr = nl80211hdr_put(msg, pid, seq, flags, NL80211_CMD_NEW_STATION);
+	if (!hdr)
+		return -1;
+
+	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, dev->ifindex);
+	NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, mac_addr);
+
+	statsattr = nla_nest_start(msg, NL80211_ATTR_STA_STATS);
+	if (!statsattr)
+		goto nla_put_failure;
+	if (stats->filled & STATION_STAT_INACTIVE_TIME)
+		NLA_PUT_U32(msg, NL80211_STA_STAT_INACTIVE_TIME,
+			    stats->inactive_time);
+	if (stats->filled & STATION_STAT_RX_BYTES)
+		NLA_PUT_U32(msg, NL80211_STA_STAT_RX_BYTES,
+			    stats->rx_bytes);
+	if (stats->filled & STATION_STAT_TX_BYTES)
+		NLA_PUT_U32(msg, NL80211_STA_STAT_TX_BYTES,
+			    stats->tx_bytes);
+
+	nla_nest_end(msg, statsattr);
+
+	return genlmsg_end(msg, hdr);
+
+ nla_put_failure:
+	return genlmsg_cancel(msg, hdr);
+}
+
+
+static int nl80211_get_station(struct sk_buff *skb, struct genl_info *info)
+{
+	struct cfg80211_registered_device *drv;
+	int err;
+	struct net_device *dev;
+	struct station_stats stats;
+	struct sk_buff *msg;
+	u8 *mac_addr = NULL;
+
+	memset(&stats, 0, sizeof(stats));
+
+	if (!info->attrs[NL80211_ATTR_MAC])
+		return -EINVAL;
+
+	mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
+
+	err = get_drv_dev_by_info_ifindex(info, &drv, &dev);
+	if (err)
+		return err;
+
+	if (!drv->ops->get_station) {
+		err = -EOPNOTSUPP;
+		goto out;
+	}
+
+	rtnl_lock();
+	err = drv->ops->get_station(&drv->wiphy, dev, mac_addr, &stats);
+	rtnl_unlock();
+
+	msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
+	if (!msg)
+		goto out;
+
+	if (nl80211_send_station(msg, info->snd_pid, info->snd_seq, 0,
+				 dev, mac_addr, &stats) < 0)
+		goto out_free;
+
+	err = genlmsg_unicast(msg, info->snd_pid);
+	goto out;
+
+ out_free:
+	nlmsg_free(msg);
+
+ out:
+	cfg80211_put_dev(drv);
+	dev_put(dev);
+	return err;
+}
+
+/*
+ * Get vlan interface making sure it is on the right wiphy.
+ */
+static int get_vlan(struct nlattr *vlanattr,
+		    struct cfg80211_registered_device *rdev,
+		    struct net_device **vlan)
+{
+	*vlan = NULL;
+
+	if (vlanattr) {
+		*vlan = dev_get_by_index(&init_net, nla_get_u32(vlanattr));
+		if (!*vlan)
+			return -ENODEV;
+		if (!(*vlan)->ieee80211_ptr)
+			return -EINVAL;
+		if ((*vlan)->ieee80211_ptr->wiphy != &rdev->wiphy)
+			return -EINVAL;
+	}
+	return 0;
+}
+
+static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info)
+{
+	struct cfg80211_registered_device *drv;
+	int err;
+	struct net_device *dev;
+	struct station_parameters params;
+	u8 *mac_addr = NULL;
+
+	memset(&params, 0, sizeof(params));
+
+	params.listen_interval = -1;
+
+	if (info->attrs[NL80211_ATTR_STA_AID])
+		return -EINVAL;
+
+	if (!info->attrs[NL80211_ATTR_MAC])
+		return -EINVAL;
+
+	mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
+
+	if (info->attrs[NL80211_ATTR_STA_SUPPORTED_RATES]) {
+		params.supported_rates =
+			nla_data(info->attrs[NL80211_ATTR_STA_SUPPORTED_RATES]);
+		params.supported_rates_len =
+			nla_len(info->attrs[NL80211_ATTR_STA_SUPPORTED_RATES]);
+	}
+
+	if (info->attrs[NL80211_ATTR_STA_LISTEN_INTERVAL])
+		params.listen_interval =
+		    nla_get_u16(info->attrs[NL80211_ATTR_STA_LISTEN_INTERVAL]);
+
+	if (parse_station_flags(info->attrs[NL80211_ATTR_STA_FLAGS],
+				&params.station_flags))
+		return -EINVAL;
+
+	err = get_drv_dev_by_info_ifindex(info, &drv, &dev);
+	if (err)
+		return err;
+
+	err = get_vlan(info->attrs[NL80211_ATTR_STA_VLAN], drv, &params.vlan);
+	if (err)
+		goto out;
+
+	if (!drv->ops->change_station) {
+		err = -EOPNOTSUPP;
+		goto out;
+	}
+
+	rtnl_lock();
+	err = drv->ops->change_station(&drv->wiphy, dev, mac_addr, &params);
+	rtnl_unlock();
+
+ out:
+	if (params.vlan)
+		dev_put(params.vlan);
+	cfg80211_put_dev(drv);
+	dev_put(dev);
+	return err;
+}
+
+static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info)
+{
+	struct cfg80211_registered_device *drv;
+	int err;
+	struct net_device *dev;
+	struct station_parameters params;
+	u8 *mac_addr = NULL;
+
+	memset(&params, 0, sizeof(params));
+
+	if (!info->attrs[NL80211_ATTR_MAC])
+		return -EINVAL;
+
+	if (!info->attrs[NL80211_ATTR_STA_AID])
+		return -EINVAL;
+
+	if (!info->attrs[NL80211_ATTR_STA_LISTEN_INTERVAL])
+		return -EINVAL;
+
+	if (!info->attrs[NL80211_ATTR_STA_SUPPORTED_RATES])
+		return -EINVAL;
+
+	mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
+	params.supported_rates =
+		nla_data(info->attrs[NL80211_ATTR_STA_SUPPORTED_RATES]);
+	params.supported_rates_len =
+		nla_len(info->attrs[NL80211_ATTR_STA_SUPPORTED_RATES]);
+	params.listen_interval =
+		nla_get_u16(info->attrs[NL80211_ATTR_STA_LISTEN_INTERVAL]);
+	params.listen_interval = nla_get_u16(info->attrs[NL80211_ATTR_STA_AID]);
+
+	if (parse_station_flags(info->attrs[NL80211_ATTR_STA_FLAGS],
+				&params.station_flags))
+		return -EINVAL;
+
+	err = get_drv_dev_by_info_ifindex(info, &drv, &dev);
+	if (err)
+		return err;
+
+	err = get_vlan(info->attrs[NL80211_ATTR_STA_VLAN], drv, &params.vlan);
+	if (err)
+		goto out;
+
+	if (!drv->ops->add_station) {
+		err = -EOPNOTSUPP;
+		goto out;
+	}
+
+	rtnl_lock();
+	err = drv->ops->add_station(&drv->wiphy, dev, mac_addr, &params);
+	rtnl_unlock();
+
+ out:
+	if (params.vlan)
+		dev_put(params.vlan);
+	cfg80211_put_dev(drv);
+	dev_put(dev);
+	return err;
+}
+
+static int nl80211_del_station(struct sk_buff *skb, struct genl_info *info)
+{
+	struct cfg80211_registered_device *drv;
+	int err;
+	struct net_device *dev;
+	u8 *mac_addr = NULL;
+
+	if (info->attrs[NL80211_ATTR_MAC])
+		mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
+
+	err = get_drv_dev_by_info_ifindex(info, &drv, &dev);
+	if (err)
+		return err;
+
+	if (!drv->ops->del_station) {
+		err = -EOPNOTSUPP;
+		goto out;
+	}
+
+	rtnl_lock();
+	err = drv->ops->del_station(&drv->wiphy, dev, mac_addr);
+	rtnl_unlock();
+
+ out:
+	cfg80211_put_dev(drv);
+	dev_put(dev);
+	return err;
+}
+
 static struct genl_ops nl80211_ops[] = {
 	{
 		.cmd = NL80211_CMD_GET_WIPHY,
@@ -374,6 +1158,73 @@ static struct genl_ops nl80211_ops[] = {
 		.policy = nl80211_policy,
 		.flags = GENL_ADMIN_PERM,
 	},
+	{
+		.cmd = NL80211_CMD_GET_KEY,
+		.doit = nl80211_get_key,
+		.policy = nl80211_policy,
+		.flags = GENL_ADMIN_PERM,
+	},
+	{
+		.cmd = NL80211_CMD_SET_KEY,
+		.doit = nl80211_set_key,
+		.policy = nl80211_policy,
+		.flags = GENL_ADMIN_PERM,
+	},
+	{
+		.cmd = NL80211_CMD_NEW_KEY,
+		.doit = nl80211_new_key,
+		.policy = nl80211_policy,
+		.flags = GENL_ADMIN_PERM,
+	},
+	{
+		.cmd = NL80211_CMD_DEL_KEY,
+		.doit = nl80211_del_key,
+		.policy = nl80211_policy,
+		.flags = GENL_ADMIN_PERM,
+	},
+	{
+		.cmd = NL80211_CMD_SET_BEACON,
+		.policy = nl80211_policy,
+		.flags = GENL_ADMIN_PERM,
+		.doit = nl80211_addset_beacon,
+	},
+	{
+		.cmd = NL80211_CMD_NEW_BEACON,
+		.policy = nl80211_policy,
+		.flags = GENL_ADMIN_PERM,
+		.doit = nl80211_addset_beacon,
+	},
+	{
+		.cmd = NL80211_CMD_DEL_BEACON,
+		.policy = nl80211_policy,
+		.flags = GENL_ADMIN_PERM,
+		.doit = nl80211_del_beacon,
+	},
+	{
+		.cmd = NL80211_CMD_GET_STATION,
+		.doit = nl80211_get_station,
+		/* TODO: implement dumpit */
+		.policy = nl80211_policy,
+		.flags = GENL_ADMIN_PERM,
+	},
+	{
+		.cmd = NL80211_CMD_SET_STATION,
+		.doit = nl80211_set_station,
+		.policy = nl80211_policy,
+		.flags = GENL_ADMIN_PERM,
+	},
+	{
+		.cmd = NL80211_CMD_NEW_STATION,
+		.doit = nl80211_new_station,
+		.policy = nl80211_policy,
+		.flags = GENL_ADMIN_PERM,
+	},
+	{
+		.cmd = NL80211_CMD_DEL_STATION,
+		.doit = nl80211_del_station,
+		.policy = nl80211_policy,
+		.flags = GENL_ADMIN_PERM,
+	},
 };
 
 /* multicast groups */
diff --git a/package/mac80211/src/net/wireless/reg.c b/package/mac80211/src/net/wireless/reg.c
new file mode 100644
index 0000000000..2b63c96dcf
--- /dev/null
+++ b/package/mac80211/src/net/wireless/reg.c
@@ -0,0 +1,153 @@
+/*
+ * Copyright 2002-2005, Instant802 Networks, Inc.
+ * Copyright 2005-2006, Devicescape Software, Inc.
+ * Copyright 2007	Johannes Berg <johannes@sipsolutions.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+/*
+ * This regulatory domain control implementation is highly incomplete, it
+ * only exists for the purpose of not regressing mac80211.
+ *
+ * For now, drivers can restrict the set of allowed channels by either
+ * not registering those channels or setting the IEEE80211_CHAN_DISABLED
+ * flag; that flag will only be *set* by this code, never *cleared.
+ *
+ * The usual implementation is for a driver to read a device EEPROM to
+ * determine which regulatory domain it should be operating under, then
+ * looking up the allowable channels in a driver-local table and finally
+ * registering those channels in the wiphy structure.
+ *
+ * Alternatively, drivers that trust the regulatory domain control here
+ * will register a complete set of capabilities and the control code
+ * will restrict the set by setting the IEEE80211_CHAN_* flags.
+ */
+#include <linux/kernel.h>
+#include <net/wireless.h>
+#include "core.h"
+
+static char *ieee80211_regdom = "US";
+module_param(ieee80211_regdom, charp, 0444);
+MODULE_PARM_DESC(ieee80211_regdom, "IEEE 802.11 regulatory domain code");
+
+struct ieee80211_channel_range {
+	short start_freq;
+	short end_freq;
+	int max_power;
+	int max_antenna_gain;
+	u32 flags;
+};
+
+struct ieee80211_regdomain {
+	const char *code;
+	const struct ieee80211_channel_range *ranges;
+	int n_ranges;
+};
+
+#define RANGE_PWR(_start, _end, _pwr, _ag, _flags)	\
+	{ _start, _end, _pwr, _ag, _flags }
+
+
+/*
+ * Ideally, in the future, these definitions will be loaded from a
+ * userspace table via some daemon.
+ */
+static const struct ieee80211_channel_range ieee80211_US_channels[] = {
+	/* IEEE 802.11b/g, channels 1..11 */
+	RANGE_PWR(2412, 2462, 27, 6, 0),
+	/* IEEE 802.11a, channels 52..64 */
+	RANGE_PWR(5260, 5320, 23, 6, 0),
+	/* IEEE 802.11a, channels 149..165, outdoor */
+	RANGE_PWR(5745, 5825, 30, 6, 0),
+};
+
+static const struct ieee80211_channel_range ieee80211_JP_channels[] = {
+	/* IEEE 802.11b/g, channels 1..14 */
+	RANGE_PWR(2412, 2484, 20, 6, 0),
+	/* IEEE 802.11a, channels 34..48 */
+	RANGE_PWR(5170, 5240, 20, 6, IEEE80211_CHAN_PASSIVE_SCAN),
+	/* IEEE 802.11a, channels 52..64 */
+	RANGE_PWR(5260, 5320, 20, 6, IEEE80211_CHAN_NO_IBSS |
+				     IEEE80211_CHAN_RADAR),
+};
+
+#define REGDOM(_code)							\
+	{								\
+		.code = __stringify(_code),				\
+		.ranges = ieee80211_ ##_code## _channels,		\
+		.n_ranges = ARRAY_SIZE(ieee80211_ ##_code## _channels),	\
+	}
+
+static const struct ieee80211_regdomain ieee80211_regdoms[] = {
+	REGDOM(US),
+	REGDOM(JP),
+};
+
+
+static const struct ieee80211_regdomain *get_regdom(void)
+{
+	static const struct ieee80211_channel_range
+	ieee80211_world_channels[] = {
+		/* IEEE 802.11b/g, channels 1..11 */
+		RANGE_PWR(2412, 2462, 27, 6, 0),
+	};
+	static const struct ieee80211_regdomain regdom_world = REGDOM(world);
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(ieee80211_regdoms); i++)
+		if (strcmp(ieee80211_regdom, ieee80211_regdoms[i].code) == 0)
+			return &ieee80211_regdoms[i];
+
+	return &regdom_world;
+}
+
+
+static void handle_channel(struct ieee80211_channel *chan,
+			   const struct ieee80211_regdomain *rd)
+{
+	int i;
+	u32 flags = chan->orig_flags;
+	const struct ieee80211_channel_range *rg = NULL;
+
+	for (i = 0; i < rd->n_ranges; i++) {
+		if (rd->ranges[i].start_freq <= chan->center_freq &&
+		    chan->center_freq <= rd->ranges[i].end_freq) {
+			rg = &rd->ranges[i];
+			break;
+		}
+	}
+
+	if (!rg) {
+		/* not found */
+		flags |= IEEE80211_CHAN_DISABLED;
+		chan->flags = flags;
+		return;
+	}
+
+	chan->flags = flags;
+	chan->max_antenna_gain = min(chan->orig_mag,
+					 rg->max_antenna_gain);
+	chan->max_power = min(chan->orig_mpwr, rg->max_power);
+}
+
+static void handle_band(struct ieee80211_supported_band *sband,
+			const struct ieee80211_regdomain *rd)
+{
+	int i;
+
+	for (i = 0; i < sband->n_channels; i++)
+		handle_channel(&sband->channels[i], rd);
+}
+
+void wiphy_update_regulatory(struct wiphy *wiphy)
+{
+	enum ieee80211_band band;
+	const struct ieee80211_regdomain *rd = get_regdom();
+
+	for (band = 0; band < IEEE80211_NUM_BANDS; band++)
+		if (wiphy->bands[band])
+			handle_band(wiphy->bands[band], rd);
+}
diff --git a/package/mac80211/src/net/wireless/sysfs.c b/package/mac80211/src/net/wireless/sysfs.c
index 2d5d2255a2..29f820e182 100644
--- a/package/mac80211/src/net/wireless/sysfs.c
+++ b/package/mac80211/src/net/wireless/sysfs.c
@@ -53,8 +53,7 @@ static void wiphy_dev_release(struct device *dev)
 }
 
 #ifdef CONFIG_HOTPLUG
-static int wiphy_uevent(struct device *dev, char **envp,
-			int num_envp, char *buf, int size)
+static int wiphy_uevent(struct device *dev, struct kobj_uevent_env *env)
 {
 	/* TODO, we probably need stuff here */
 	return 0;
diff --git a/package/mac80211/src/net/wireless/util.c b/package/mac80211/src/net/wireless/util.c
new file mode 100644
index 0000000000..77336c22fc
--- /dev/null
+++ b/package/mac80211/src/net/wireless/util.c
@@ -0,0 +1,98 @@
+/*
+ * Wireless utility functions
+ *
+ * Copyright 2007	Johannes Berg <johannes@sipsolutions.net>
+ */
+#include <net/wireless.h>
+#include <asm/bitops.h>
+#include "core.h"
+
+int ieee80211_channel_to_frequency(int chan)
+{
+	if (chan < 14)
+		return 2407 + chan * 5;
+
+	if (chan == 14)
+		return 2484;
+
+	/* FIXME: 802.11j 17.3.8.3.2 */
+	return (chan + 1000) * 5;
+}
+EXPORT_SYMBOL(ieee80211_channel_to_frequency);
+
+int ieee80211_frequency_to_channel(int freq)
+{
+	if (freq == 2484)
+		return 14;
+
+	if (freq < 2484)
+		return (freq - 2407) / 5;
+
+	/* FIXME: 802.11j 17.3.8.3.2 */
+	return freq/5 - 1000;
+}
+EXPORT_SYMBOL(ieee80211_frequency_to_channel);
+
+static void set_mandatory_flags_band(struct ieee80211_supported_band *sband,
+				     enum ieee80211_band band)
+{
+	int i, want;
+
+	switch (band) {
+	case IEEE80211_BAND_5GHZ:
+		want = 3;
+		for (i = 0; i < sband->n_bitrates; i++) {
+			if (sband->bitrates[i].bitrate == 60 ||
+			    sband->bitrates[i].bitrate == 120 ||
+			    sband->bitrates[i].bitrate == 240) {
+				sband->bitrates[i].flags |=
+					IEEE80211_RATE_MANDATORY_A;
+				want--;
+			}
+		}
+		WARN_ON(want);
+		break;
+	case IEEE80211_BAND_2GHZ:
+		want = 7;
+		for (i = 0; i < sband->n_bitrates; i++) {
+			if (sband->bitrates[i].bitrate == 10) {
+				sband->bitrates[i].flags |=
+					IEEE80211_RATE_MANDATORY_B |
+					IEEE80211_RATE_MANDATORY_G;
+				want--;
+			}
+
+			if (sband->bitrates[i].bitrate == 20 ||
+			    sband->bitrates[i].bitrate == 55 ||
+			    sband->bitrates[i].bitrate == 110 ||
+			    sband->bitrates[i].bitrate == 60 ||
+			    sband->bitrates[i].bitrate == 120 ||
+			    sband->bitrates[i].bitrate == 240) {
+				sband->bitrates[i].flags |=
+					IEEE80211_RATE_MANDATORY_G;
+				want--;
+			}
+
+			if (sband->bitrates[i].bitrate != 10 &&
+			    sband->bitrates[i].bitrate != 20 &&
+			    sband->bitrates[i].bitrate != 55 &&
+			    sband->bitrates[i].bitrate != 110)
+				sband->bitrates[i].flags |=
+					IEEE80211_RATE_ERP_G;
+		}
+		WARN_ON(want != 0 && want != 3 && want != 6);
+		break;
+	case IEEE80211_NUM_BANDS:
+		WARN_ON(1);
+		break;
+	}
+}
+
+void ieee80211_set_bitrate_flags(struct wiphy *wiphy)
+{
+	enum ieee80211_band band;
+
+	for (band = 0; band < IEEE80211_NUM_BANDS; band++)
+		if (wiphy->bands[band])
+			set_mandatory_flags_band(wiphy->bands[band], band);
+}
diff --git a/package/mac80211/src/net/wireless/wext.c b/package/mac80211/src/net/wireless/wext.c
new file mode 100644
index 0000000000..a2d496f0b3
--- /dev/null
+++ b/package/mac80211/src/net/wireless/wext.c
@@ -0,0 +1,1522 @@
+/*
+ * This file implement the Wireless Extensions APIs.
+ *
+ * Authors :	Jean Tourrilhes - HPL - <jt@hpl.hp.com>
+ * Copyright (c) 1997-2007 Jean Tourrilhes, All Rights Reserved.
+ *
+ * (As all part of the Linux kernel, this file is GPL)
+ */
+
+/************************** DOCUMENTATION **************************/
+/*
+ * API definition :
+ * --------------
+ * See <linux/wireless.h> for details of the APIs and the rest.
+ *
+ * History :
+ * -------
+ *
+ * v1 - 5.12.01 - Jean II
+ *	o Created this file.
+ *
+ * v2 - 13.12.01 - Jean II
+ *	o Move /proc/net/wireless stuff from net/core/dev.c to here
+ *	o Make Wireless Extension IOCTLs go through here
+ *	o Added iw_handler handling ;-)
+ *	o Added standard ioctl description
+ *	o Initial dumb commit strategy based on orinoco.c
+ *
+ * v3 - 19.12.01 - Jean II
+ *	o Make sure we don't go out of standard_ioctl[] in ioctl_standard_call
+ *	o Add event dispatcher function
+ *	o Add event description
+ *	o Propagate events as rtnetlink IFLA_WIRELESS option
+ *	o Generate event on selected SET requests
+ *
+ * v4 - 18.04.02 - Jean II
+ *	o Fix stupid off by one in iw_ioctl_description : IW_ESSID_MAX_SIZE + 1
+ *
+ * v5 - 21.06.02 - Jean II
+ *	o Add IW_PRIV_TYPE_ADDR in priv_type_size (+cleanup)
+ *	o Reshuffle IW_HEADER_TYPE_XXX to map IW_PRIV_TYPE_XXX changes
+ *	o Add IWEVCUSTOM for driver specific event/scanning token
+ *	o Turn on WE_STRICT_WRITE by default + kernel warning
+ *	o Fix WE_STRICT_WRITE in ioctl_export_private() (32 => iw_num)
+ *	o Fix off-by-one in test (extra_size <= IFNAMSIZ)
+ *
+ * v6 - 9.01.03 - Jean II
+ *	o Add common spy support : iw_handler_set_spy(), wireless_spy_update()
+ *	o Add enhanced spy support : iw_handler_set_thrspy() and event.
+ *	o Add WIRELESS_EXT version display in /proc/net/wireless
+ *
+ * v6 - 18.06.04 - Jean II
+ *	o Change get_spydata() method for added safety
+ *	o Remove spy #ifdef, they are always on -> cleaner code
+ *	o Allow any size GET request if user specifies length > max
+ *		and if request has IW_DESCR_FLAG_NOMAX flag or is SIOCGIWPRIV
+ *	o Start migrating get_wireless_stats to struct iw_handler_def
+ *	o Add wmb() in iw_handler_set_spy() for non-coherent archs/cpus
+ * Based on patch from Pavel Roskin <proski@gnu.org> :
+ *	o Fix kernel data leak to user space in private handler handling
+ *
+ * v7 - 18.3.05 - Jean II
+ *	o Remove (struct iw_point *)->pointer from events and streams
+ *	o Remove spy_offset from struct iw_handler_def
+ *	o Start deprecating dev->get_wireless_stats, output a warning
+ *	o If IW_QUAL_DBM is set, show dBm values in /proc/net/wireless
+ *	o Don't loose INVALID/DBM flags when clearing UPDATED flags (iwstats)
+ *
+ * v8 - 17.02.06 - Jean II
+ *	o RtNetlink requests support (SET/GET)
+ *
+ * v8b - 03.08.06 - Herbert Xu
+ *	o Fix Wireless Event locking issues.
+ *
+ * v9 - 14.3.06 - Jean II
+ *	o Change length in ESSID and NICK to strlen() instead of strlen()+1
+ *	o Make standard_ioctl_num and standard_event_num unsigned
+ *	o Remove (struct net_device *)->get_wireless_stats()
+ *
+ * v10 - 16.3.07 - Jean II
+ *	o Prevent leaking of kernel space in stream on 64 bits.
+ */
+
+/***************************** INCLUDES *****************************/
+
+#include <linux/module.h>
+#include <linux/types.h>		/* off_t */
+#include <linux/netdevice.h>		/* struct ifreq, dev_get_by_name() */
+#include <linux/proc_fs.h>
+#include <linux/rtnetlink.h>		/* rtnetlink stuff */
+#include <linux/seq_file.h>
+#include <linux/init.h>			/* for __init */
+#include <linux/if_arp.h>		/* ARPHRD_ETHER */
+#include <linux/etherdevice.h>		/* compare_ether_addr */
+#include <linux/interrupt.h>
+#include <net/net_namespace.h>
+
+#include <linux/wireless.h>		/* Pretty obvious */
+#include <net/iw_handler.h>		/* New driver API */
+#include <net/netlink.h>
+#include <net/wext.h>
+
+#include <asm/uaccess.h>		/* copy_to_user() */
+
+/************************* GLOBAL VARIABLES *************************/
+/*
+ * You should not use global variables, because of re-entrancy.
+ * On our case, it's only const, so it's OK...
+ */
+/*
+ * Meta-data about all the standard Wireless Extension request we
+ * know about.
+ */
+static const struct iw_ioctl_description standard_ioctl[] = {
+	[SIOCSIWCOMMIT	- SIOCIWFIRST] = {
+		.header_type	= IW_HEADER_TYPE_NULL,
+	},
+	[SIOCGIWNAME	- SIOCIWFIRST] = {
+		.header_type	= IW_HEADER_TYPE_CHAR,
+		.flags		= IW_DESCR_FLAG_DUMP,
+	},
+	[SIOCSIWNWID	- SIOCIWFIRST] = {
+		.header_type	= IW_HEADER_TYPE_PARAM,
+		.flags		= IW_DESCR_FLAG_EVENT,
+	},
+	[SIOCGIWNWID	- SIOCIWFIRST] = {
+		.header_type	= IW_HEADER_TYPE_PARAM,
+		.flags		= IW_DESCR_FLAG_DUMP,
+	},
+	[SIOCSIWFREQ	- SIOCIWFIRST] = {
+		.header_type	= IW_HEADER_TYPE_FREQ,
+		.flags		= IW_DESCR_FLAG_EVENT,
+	},
+	[SIOCGIWFREQ	- SIOCIWFIRST] = {
+		.header_type	= IW_HEADER_TYPE_FREQ,
+		.flags		= IW_DESCR_FLAG_DUMP,
+	},
+	[SIOCSIWMODE	- SIOCIWFIRST] = {
+		.header_type	= IW_HEADER_TYPE_UINT,
+		.flags		= IW_DESCR_FLAG_EVENT,
+	},
+	[SIOCGIWMODE	- SIOCIWFIRST] = {
+		.header_type	= IW_HEADER_TYPE_UINT,
+		.flags		= IW_DESCR_FLAG_DUMP,
+	},
+	[SIOCSIWSENS	- SIOCIWFIRST] = {
+		.header_type	= IW_HEADER_TYPE_PARAM,
+	},
+	[SIOCGIWSENS	- SIOCIWFIRST] = {
+		.header_type	= IW_HEADER_TYPE_PARAM,
+	},
+	[SIOCSIWRANGE	- SIOCIWFIRST] = {
+		.header_type	= IW_HEADER_TYPE_NULL,
+	},
+	[SIOCGIWRANGE	- SIOCIWFIRST] = {
+		.header_type	= IW_HEADER_TYPE_POINT,
+		.token_size	= 1,
+		.max_tokens	= sizeof(struct iw_range),
+		.flags		= IW_DESCR_FLAG_DUMP,
+	},
+	[SIOCSIWPRIV	- SIOCIWFIRST] = {
+		.header_type	= IW_HEADER_TYPE_NULL,
+	},
+	[SIOCGIWPRIV	- SIOCIWFIRST] = { /* (handled directly by us) */
+		.header_type	= IW_HEADER_TYPE_POINT,
+		.token_size	= sizeof(struct iw_priv_args),
+		.max_tokens	= 16,
+		.flags		= IW_DESCR_FLAG_NOMAX,
+	},
+	[SIOCSIWSTATS	- SIOCIWFIRST] = {
+		.header_type	= IW_HEADER_TYPE_NULL,
+	},
+	[SIOCGIWSTATS	- SIOCIWFIRST] = { /* (handled directly by us) */
+		.header_type	= IW_HEADER_TYPE_POINT,
+		.token_size	= 1,
+		.max_tokens	= sizeof(struct iw_statistics),
+		.flags		= IW_DESCR_FLAG_DUMP,
+	},
+	[SIOCSIWSPY	- SIOCIWFIRST] = {
+		.header_type	= IW_HEADER_TYPE_POINT,
+		.token_size	= sizeof(struct sockaddr),
+		.max_tokens	= IW_MAX_SPY,
+	},
+	[SIOCGIWSPY	- SIOCIWFIRST] = {
+		.header_type	= IW_HEADER_TYPE_POINT,
+		.token_size	= sizeof(struct sockaddr) +
+				  sizeof(struct iw_quality),
+		.max_tokens	= IW_MAX_SPY,
+	},
+	[SIOCSIWTHRSPY	- SIOCIWFIRST] = {
+		.header_type	= IW_HEADER_TYPE_POINT,
+		.token_size	= sizeof(struct iw_thrspy),
+		.min_tokens	= 1,
+		.max_tokens	= 1,
+	},
+	[SIOCGIWTHRSPY	- SIOCIWFIRST] = {
+		.header_type	= IW_HEADER_TYPE_POINT,
+		.token_size	= sizeof(struct iw_thrspy),
+		.min_tokens	= 1,
+		.max_tokens	= 1,
+	},
+	[SIOCSIWAP	- SIOCIWFIRST] = {
+		.header_type	= IW_HEADER_TYPE_ADDR,
+	},
+	[SIOCGIWAP	- SIOCIWFIRST] = {
+		.header_type	= IW_HEADER_TYPE_ADDR,
+		.flags		= IW_DESCR_FLAG_DUMP,
+	},
+	[SIOCSIWMLME	- SIOCIWFIRST] = {
+		.header_type	= IW_HEADER_TYPE_POINT,
+		.token_size	= 1,
+		.min_tokens	= sizeof(struct iw_mlme),
+		.max_tokens	= sizeof(struct iw_mlme),
+	},
+	[SIOCGIWAPLIST	- SIOCIWFIRST] = {
+		.header_type	= IW_HEADER_TYPE_POINT,
+		.token_size	= sizeof(struct sockaddr) +
+				  sizeof(struct iw_quality),
+		.max_tokens	= IW_MAX_AP,
+		.flags		= IW_DESCR_FLAG_NOMAX,
+	},
+	[SIOCSIWSCAN	- SIOCIWFIRST] = {
+		.header_type	= IW_HEADER_TYPE_POINT,
+		.token_size	= 1,
+		.min_tokens	= 0,
+		.max_tokens	= sizeof(struct iw_scan_req),
+	},
+	[SIOCGIWSCAN	- SIOCIWFIRST] = {
+		.header_type	= IW_HEADER_TYPE_POINT,
+		.token_size	= 1,
+		.max_tokens	= IW_SCAN_MAX_DATA,
+		.flags		= IW_DESCR_FLAG_NOMAX,
+	},
+	[SIOCSIWESSID	- SIOCIWFIRST] = {
+		.header_type	= IW_HEADER_TYPE_POINT,
+		.token_size	= 1,
+		.max_tokens	= IW_ESSID_MAX_SIZE,
+		.flags		= IW_DESCR_FLAG_EVENT,
+	},
+	[SIOCGIWESSID	- SIOCIWFIRST] = {
+		.header_type	= IW_HEADER_TYPE_POINT,
+		.token_size	= 1,
+		.max_tokens	= IW_ESSID_MAX_SIZE,
+		.flags		= IW_DESCR_FLAG_DUMP,
+	},
+	[SIOCSIWNICKN	- SIOCIWFIRST] = {
+		.header_type	= IW_HEADER_TYPE_POINT,
+		.token_size	= 1,
+		.max_tokens	= IW_ESSID_MAX_SIZE,
+	},
+	[SIOCGIWNICKN	- SIOCIWFIRST] = {
+		.header_type	= IW_HEADER_TYPE_POINT,
+		.token_size	= 1,
+		.max_tokens	= IW_ESSID_MAX_SIZE,
+	},
+	[SIOCSIWRATE	- SIOCIWFIRST] = {
+		.header_type	= IW_HEADER_TYPE_PARAM,
+	},
+	[SIOCGIWRATE	- SIOCIWFIRST] = {
+		.header_type	= IW_HEADER_TYPE_PARAM,
+	},
+	[SIOCSIWRTS	- SIOCIWFIRST] = {
+		.header_type	= IW_HEADER_TYPE_PARAM,
+	},
+	[SIOCGIWRTS	- SIOCIWFIRST] = {
+		.header_type	= IW_HEADER_TYPE_PARAM,
+	},
+	[SIOCSIWFRAG	- SIOCIWFIRST] = {
+		.header_type	= IW_HEADER_TYPE_PARAM,
+	},
+	[SIOCGIWFRAG	- SIOCIWFIRST] = {
+		.header_type	= IW_HEADER_TYPE_PARAM,
+	},
+	[SIOCSIWTXPOW	- SIOCIWFIRST] = {
+		.header_type	= IW_HEADER_TYPE_PARAM,
+	},
+	[SIOCGIWTXPOW	- SIOCIWFIRST] = {
+		.header_type	= IW_HEADER_TYPE_PARAM,
+	},
+	[SIOCSIWRETRY	- SIOCIWFIRST] = {
+		.header_type	= IW_HEADER_TYPE_PARAM,
+	},
+	[SIOCGIWRETRY	- SIOCIWFIRST] = {
+		.header_type	= IW_HEADER_TYPE_PARAM,
+	},
+	[SIOCSIWENCODE	- SIOCIWFIRST] = {
+		.header_type	= IW_HEADER_TYPE_POINT,
+		.token_size	= 1,
+		.max_tokens	= IW_ENCODING_TOKEN_MAX,
+		.flags		= IW_DESCR_FLAG_EVENT | IW_DESCR_FLAG_RESTRICT,
+	},
+	[SIOCGIWENCODE	- SIOCIWFIRST] = {
+		.header_type	= IW_HEADER_TYPE_POINT,
+		.token_size	= 1,
+		.max_tokens	= IW_ENCODING_TOKEN_MAX,
+		.flags		= IW_DESCR_FLAG_DUMP | IW_DESCR_FLAG_RESTRICT,
+	},
+	[SIOCSIWPOWER	- SIOCIWFIRST] = {
+		.header_type	= IW_HEADER_TYPE_PARAM,
+	},
+	[SIOCGIWPOWER	- SIOCIWFIRST] = {
+		.header_type	= IW_HEADER_TYPE_PARAM,
+	},
+	[SIOCSIWGENIE	- SIOCIWFIRST] = {
+		.header_type	= IW_HEADER_TYPE_POINT,
+		.token_size	= 1,
+		.max_tokens	= IW_GENERIC_IE_MAX,
+	},
+	[SIOCGIWGENIE	- SIOCIWFIRST] = {
+		.header_type	= IW_HEADER_TYPE_POINT,
+		.token_size	= 1,
+		.max_tokens	= IW_GENERIC_IE_MAX,
+	},
+	[SIOCSIWAUTH	- SIOCIWFIRST] = {
+		.header_type	= IW_HEADER_TYPE_PARAM,
+	},
+	[SIOCGIWAUTH	- SIOCIWFIRST] = {
+		.header_type	= IW_HEADER_TYPE_PARAM,
+	},
+	[SIOCSIWENCODEEXT - SIOCIWFIRST] = {
+		.header_type	= IW_HEADER_TYPE_POINT,
+		.token_size	= 1,
+		.min_tokens	= sizeof(struct iw_encode_ext),
+		.max_tokens	= sizeof(struct iw_encode_ext) +
+				  IW_ENCODING_TOKEN_MAX,
+	},
+	[SIOCGIWENCODEEXT - SIOCIWFIRST] = {
+		.header_type	= IW_HEADER_TYPE_POINT,
+		.token_size	= 1,
+		.min_tokens	= sizeof(struct iw_encode_ext),
+		.max_tokens	= sizeof(struct iw_encode_ext) +
+				  IW_ENCODING_TOKEN_MAX,
+	},
+	[SIOCSIWPMKSA - SIOCIWFIRST] = {
+		.header_type	= IW_HEADER_TYPE_POINT,
+		.token_size	= 1,
+		.min_tokens	= sizeof(struct iw_pmksa),
+		.max_tokens	= sizeof(struct iw_pmksa),
+	},
+};
+static const unsigned standard_ioctl_num = ARRAY_SIZE(standard_ioctl);
+
+/*
+ * Meta-data about all the additional standard Wireless Extension events
+ * we know about.
+ */
+static const struct iw_ioctl_description standard_event[] = {
+	[IWEVTXDROP	- IWEVFIRST] = {
+		.header_type	= IW_HEADER_TYPE_ADDR,
+	},
+	[IWEVQUAL	- IWEVFIRST] = {
+		.header_type	= IW_HEADER_TYPE_QUAL,
+	},
+	[IWEVCUSTOM	- IWEVFIRST] = {
+		.header_type	= IW_HEADER_TYPE_POINT,
+		.token_size	= 1,
+		.max_tokens	= IW_CUSTOM_MAX,
+	},
+	[IWEVREGISTERED	- IWEVFIRST] = {
+		.header_type	= IW_HEADER_TYPE_ADDR,
+	},
+	[IWEVEXPIRED	- IWEVFIRST] = {
+		.header_type	= IW_HEADER_TYPE_ADDR,
+	},
+	[IWEVGENIE	- IWEVFIRST] = {
+		.header_type	= IW_HEADER_TYPE_POINT,
+		.token_size	= 1,
+		.max_tokens	= IW_GENERIC_IE_MAX,
+	},
+	[IWEVMICHAELMICFAILURE	- IWEVFIRST] = {
+		.header_type	= IW_HEADER_TYPE_POINT,
+		.token_size	= 1,
+		.max_tokens	= sizeof(struct iw_michaelmicfailure),
+	},
+	[IWEVASSOCREQIE	- IWEVFIRST] = {
+		.header_type	= IW_HEADER_TYPE_POINT,
+		.token_size	= 1,
+		.max_tokens	= IW_GENERIC_IE_MAX,
+	},
+	[IWEVASSOCRESPIE	- IWEVFIRST] = {
+		.header_type	= IW_HEADER_TYPE_POINT,
+		.token_size	= 1,
+		.max_tokens	= IW_GENERIC_IE_MAX,
+	},
+	[IWEVPMKIDCAND	- IWEVFIRST] = {
+		.header_type	= IW_HEADER_TYPE_POINT,
+		.token_size	= 1,
+		.max_tokens	= sizeof(struct iw_pmkid_cand),
+	},
+};
+static const unsigned standard_event_num = ARRAY_SIZE(standard_event);
+
+/* Size (in bytes) of the various private data types */
+static const char iw_priv_type_size[] = {
+	0,				/* IW_PRIV_TYPE_NONE */
+	1,				/* IW_PRIV_TYPE_BYTE */
+	1,				/* IW_PRIV_TYPE_CHAR */
+	0,				/* Not defined */
+	sizeof(__u32),			/* IW_PRIV_TYPE_INT */
+	sizeof(struct iw_freq),		/* IW_PRIV_TYPE_FLOAT */
+	sizeof(struct sockaddr),	/* IW_PRIV_TYPE_ADDR */
+	0,				/* Not defined */
+};
+
+/* Size (in bytes) of various events */
+static const int event_type_size[] = {
+	IW_EV_LCP_LEN,			/* IW_HEADER_TYPE_NULL */
+	0,
+	IW_EV_CHAR_LEN,			/* IW_HEADER_TYPE_CHAR */
+	0,
+	IW_EV_UINT_LEN,			/* IW_HEADER_TYPE_UINT */
+	IW_EV_FREQ_LEN,			/* IW_HEADER_TYPE_FREQ */
+	IW_EV_ADDR_LEN,			/* IW_HEADER_TYPE_ADDR */
+	0,
+	IW_EV_POINT_LEN,		/* Without variable payload */
+	IW_EV_PARAM_LEN,		/* IW_HEADER_TYPE_PARAM */
+	IW_EV_QUAL_LEN,			/* IW_HEADER_TYPE_QUAL */
+};
+
+
+/************************ COMMON SUBROUTINES ************************/
+/*
+ * Stuff that may be used in various place or doesn't fit in one
+ * of the section below.
+ */
+
+/* ---------------------------------------------------------------- */
+/*
+ * Return the driver handler associated with a specific Wireless Extension.
+ */
+static iw_handler get_handler(struct net_device *dev, unsigned int cmd)
+{
+	/* Don't "optimise" the following variable, it will crash */
+	unsigned int	index;		/* *MUST* be unsigned */
+
+	/* Check if we have some wireless handlers defined */
+	if (dev->wireless_handlers == NULL)
+		return NULL;
+
+	/* Try as a standard command */
+	index = cmd - SIOCIWFIRST;
+	if (index < dev->wireless_handlers->num_standard)
+		return dev->wireless_handlers->standard[index];
+
+	/* Try as a private command */
+	index = cmd - SIOCIWFIRSTPRIV;
+	if (index < dev->wireless_handlers->num_private)
+		return dev->wireless_handlers->private[index];
+
+	/* Not found */
+	return NULL;
+}
+
+/* ---------------------------------------------------------------- */
+/*
+ * Get statistics out of the driver
+ */
+static struct iw_statistics *get_wireless_stats(struct net_device *dev)
+{
+	/* New location */
+	if ((dev->wireless_handlers != NULL) &&
+	   (dev->wireless_handlers->get_wireless_stats != NULL))
+		return dev->wireless_handlers->get_wireless_stats(dev);
+
+	/* Not found */
+	return NULL;
+}
+
+/* ---------------------------------------------------------------- */
+/*
+ * Call the commit handler in the driver
+ * (if exist and if conditions are right)
+ *
+ * Note : our current commit strategy is currently pretty dumb,
+ * but we will be able to improve on that...
+ * The goal is to try to agreagate as many changes as possible
+ * before doing the commit. Drivers that will define a commit handler
+ * are usually those that need a reset after changing parameters, so
+ * we want to minimise the number of reset.
+ * A cool idea is to use a timer : at each "set" command, we re-set the
+ * timer, when the timer eventually fires, we call the driver.
+ * Hopefully, more on that later.
+ *
+ * Also, I'm waiting to see how many people will complain about the
+ * netif_running(dev) test. I'm open on that one...
+ * Hopefully, the driver will remember to do a commit in "open()" ;-)
+ */
+static int call_commit_handler(struct net_device *dev)
+{
+	if ((netif_running(dev)) &&
+	   (dev->wireless_handlers->standard[0] != NULL))
+		/* Call the commit handler on the driver */
+		return dev->wireless_handlers->standard[0](dev, NULL,
+							   NULL, NULL);
+	else
+		return 0;		/* Command completed successfully */
+}
+
+/* ---------------------------------------------------------------- */
+/*
+ * Calculate size of private arguments
+ */
+static inline int get_priv_size(__u16	args)
+{
+	int	num = args & IW_PRIV_SIZE_MASK;
+	int	type = (args & IW_PRIV_TYPE_MASK) >> 12;
+
+	return num * iw_priv_type_size[type];
+}
+
+/* ---------------------------------------------------------------- */
+/*
+ * Re-calculate the size of private arguments
+ */
+static inline int adjust_priv_size(__u16		args,
+				   union iwreq_data *	wrqu)
+{
+	int	num = wrqu->data.length;
+	int	max = args & IW_PRIV_SIZE_MASK;
+	int	type = (args & IW_PRIV_TYPE_MASK) >> 12;
+
+	/* Make sure the driver doesn't goof up */
+	if (max < num)
+		num = max;
+
+	return num * iw_priv_type_size[type];
+}
+
+/* ---------------------------------------------------------------- */
+/*
+ * Standard Wireless Handler : get wireless stats
+ *	Allow programatic access to /proc/net/wireless even if /proc
+ *	doesn't exist... Also more efficient...
+ */
+static int iw_handler_get_iwstats(struct net_device *		dev,
+				  struct iw_request_info *	info,
+				  union iwreq_data *		wrqu,
+				  char *			extra)
+{
+	/* Get stats from the driver */
+	struct iw_statistics *stats;
+
+	stats = get_wireless_stats(dev);
+	if (stats) {
+		/* Copy statistics to extra */
+		memcpy(extra, stats, sizeof(struct iw_statistics));
+		wrqu->data.length = sizeof(struct iw_statistics);
+
+		/* Check if we need to clear the updated flag */
+		if (wrqu->data.flags != 0)
+			stats->qual.updated &= ~IW_QUAL_ALL_UPDATED;
+		return 0;
+	} else
+		return -EOPNOTSUPP;
+}
+
+/* ---------------------------------------------------------------- */
+/*
+ * Standard Wireless Handler : get iwpriv definitions
+ * Export the driver private handler definition
+ * They will be picked up by tools like iwpriv...
+ */
+static int iw_handler_get_private(struct net_device *		dev,
+				  struct iw_request_info *	info,
+				  union iwreq_data *		wrqu,
+				  char *			extra)
+{
+	/* Check if the driver has something to export */
+	if ((dev->wireless_handlers->num_private_args == 0) ||
+	   (dev->wireless_handlers->private_args == NULL))
+		return -EOPNOTSUPP;
+
+	/* Check if there is enough buffer up there */
+	if (wrqu->data.length < dev->wireless_handlers->num_private_args) {
+		/* User space can't know in advance how large the buffer
+		 * needs to be. Give it a hint, so that we can support
+		 * any size buffer we want somewhat efficiently... */
+		wrqu->data.length = dev->wireless_handlers->num_private_args;
+		return -E2BIG;
+	}
+
+	/* Set the number of available ioctls. */
+	wrqu->data.length = dev->wireless_handlers->num_private_args;
+
+	/* Copy structure to the user buffer. */
+	memcpy(extra, dev->wireless_handlers->private_args,
+	       sizeof(struct iw_priv_args) * wrqu->data.length);
+
+	return 0;
+}
+
+
+/******************** /proc/net/wireless SUPPORT ********************/
+/*
+ * The /proc/net/wireless file is a human readable user-space interface
+ * exporting various wireless specific statistics from the wireless devices.
+ * This is the most popular part of the Wireless Extensions ;-)
+ *
+ * This interface is a pure clone of /proc/net/dev (in net/core/dev.c).
+ * The content of the file is basically the content of "struct iw_statistics".
+ */
+
+#ifdef CONFIG_PROC_FS
+
+/* ---------------------------------------------------------------- */
+/*
+ * Print one entry (line) of /proc/net/wireless
+ */
+static void wireless_seq_printf_stats(struct seq_file *seq,
+				      struct net_device *dev)
+{
+	/* Get stats from the driver */
+	struct iw_statistics *stats = get_wireless_stats(dev);
+
+	if (stats) {
+		seq_printf(seq, "%6s: %04x  %3d%c  %3d%c  %3d%c  %6d %6d %6d "
+				"%6d %6d   %6d\n",
+			   dev->name, stats->status, stats->qual.qual,
+			   stats->qual.updated & IW_QUAL_QUAL_UPDATED
+			   ? '.' : ' ',
+			   ((__s32) stats->qual.level) -
+			   ((stats->qual.updated & IW_QUAL_DBM) ? 0x100 : 0),
+			   stats->qual.updated & IW_QUAL_LEVEL_UPDATED
+			   ? '.' : ' ',
+			   ((__s32) stats->qual.noise) -
+			   ((stats->qual.updated & IW_QUAL_DBM) ? 0x100 : 0),
+			   stats->qual.updated & IW_QUAL_NOISE_UPDATED
+			   ? '.' : ' ',
+			   stats->discard.nwid, stats->discard.code,
+			   stats->discard.fragment, stats->discard.retries,
+			   stats->discard.misc, stats->miss.beacon);
+		stats->qual.updated &= ~IW_QUAL_ALL_UPDATED;
+	}
+}
+
+/* ---------------------------------------------------------------- */
+/*
+ * Print info for /proc/net/wireless (print all entries)
+ */
+static int wireless_seq_show(struct seq_file *seq, void *v)
+{
+	if (v == SEQ_START_TOKEN)
+		seq_printf(seq, "Inter-| sta-|   Quality        |   Discarded "
+				"packets               | Missed | WE\n"
+				" face | tus | link level noise |  nwid  "
+				"crypt   frag  retry   misc | beacon | %d\n",
+			   WIRELESS_EXT);
+	else
+		wireless_seq_printf_stats(seq, v);
+	return 0;
+}
+
+static const struct seq_operations wireless_seq_ops = {
+	.start = dev_seq_start,
+	.next  = dev_seq_next,
+	.stop  = dev_seq_stop,
+	.show  = wireless_seq_show,
+};
+
+static int wireless_seq_open(struct inode *inode, struct file *file)
+{
+	struct seq_file *seq;
+	int res;
+	res = seq_open(file, &wireless_seq_ops);
+	if (!res) {
+		seq = file->private_data;
+		seq->private = get_proc_net(inode);
+		if (!seq->private) {
+			seq_release(inode, file);
+			res = -ENXIO;
+		}
+	}
+	return res;
+}
+
+static int wireless_seq_release(struct inode *inode, struct file *file)
+{
+	struct seq_file *seq = file->private_data;
+	struct net *net = seq->private;
+	put_net(net);
+	return seq_release(inode, file);
+}
+
+static const struct file_operations wireless_seq_fops = {
+	.owner	 = THIS_MODULE,
+	.open    = wireless_seq_open,
+	.read    = seq_read,
+	.llseek  = seq_lseek,
+	.release = wireless_seq_release,
+};
+
+int wext_proc_init(struct net *net)
+{
+	/* Create /proc/net/wireless entry */
+	if (!proc_net_fops_create(net, "wireless", S_IRUGO, &wireless_seq_fops))
+		return -ENOMEM;
+
+	return 0;
+}
+
+void wext_proc_exit(struct net *net)
+{
+	proc_net_remove(net, "wireless");
+}
+#endif	/* CONFIG_PROC_FS */
+
+/************************** IOCTL SUPPORT **************************/
+/*
+ * The original user space API to configure all those Wireless Extensions
+ * is through IOCTLs.
+ * In there, we check if we need to call the new driver API (iw_handler)
+ * or just call the driver ioctl handler.
+ */
+
+/* ---------------------------------------------------------------- */
+/*
+ * Wrapper to call a standard Wireless Extension handler.
+ * We do various checks and also take care of moving data between
+ * user space and kernel space.
+ */
+static int ioctl_standard_call(struct net_device *	dev,
+			       struct ifreq *		ifr,
+			       unsigned int		cmd,
+			       iw_handler		handler)
+{
+	struct iwreq *				iwr = (struct iwreq *) ifr;
+	const struct iw_ioctl_description *	descr;
+	struct iw_request_info			info;
+	int					ret = -EINVAL;
+
+	/* Get the description of the IOCTL */
+	if ((cmd - SIOCIWFIRST) >= standard_ioctl_num)
+		return -EOPNOTSUPP;
+	descr = &(standard_ioctl[cmd - SIOCIWFIRST]);
+
+	/* Prepare the call */
+	info.cmd = cmd;
+	info.flags = 0;
+
+	/* Check if we have a pointer to user space data or not */
+	if (descr->header_type != IW_HEADER_TYPE_POINT) {
+
+		/* No extra arguments. Trivial to handle */
+		ret = handler(dev, &info, &(iwr->u), NULL);
+
+		/* Generate an event to notify listeners of the change */
+		if ((descr->flags & IW_DESCR_FLAG_EVENT) &&
+		   ((ret == 0) || (ret == -EIWCOMMIT)))
+			wireless_send_event(dev, cmd, &(iwr->u), NULL);
+	} else {
+		char *	extra;
+		int	extra_size;
+		int	user_length = 0;
+		int	err;
+		int	essid_compat = 0;
+
+		/* Calculate space needed by arguments. Always allocate
+		 * for max space. Easier, and won't last long... */
+		extra_size = descr->max_tokens * descr->token_size;
+
+		/* Check need for ESSID compatibility for WE < 21 */
+		switch (cmd) {
+		case SIOCSIWESSID:
+		case SIOCGIWESSID:
+		case SIOCSIWNICKN:
+		case SIOCGIWNICKN:
+			if (iwr->u.data.length == descr->max_tokens + 1)
+				essid_compat = 1;
+			else if (IW_IS_SET(cmd) && (iwr->u.data.length != 0)) {
+				char essid[IW_ESSID_MAX_SIZE + 1];
+
+				err = copy_from_user(essid, iwr->u.data.pointer,
+						     iwr->u.data.length *
+						     descr->token_size);
+				if (err)
+					return -EFAULT;
+
+				if (essid[iwr->u.data.length - 1] == '\0')
+					essid_compat = 1;
+			}
+			break;
+		default:
+			break;
+		}
+
+		iwr->u.data.length -= essid_compat;
+
+		/* Check what user space is giving us */
+		if (IW_IS_SET(cmd)) {
+			/* Check NULL pointer */
+			if ((iwr->u.data.pointer == NULL) &&
+			   (iwr->u.data.length != 0))
+				return -EFAULT;
+			/* Check if number of token fits within bounds */
+			if (iwr->u.data.length > descr->max_tokens)
+				return -E2BIG;
+			if (iwr->u.data.length < descr->min_tokens)
+				return -EINVAL;
+		} else {
+			/* Check NULL pointer */
+			if (iwr->u.data.pointer == NULL)
+				return -EFAULT;
+			/* Save user space buffer size for checking */
+			user_length = iwr->u.data.length;
+
+			/* Don't check if user_length > max to allow forward
+			 * compatibility. The test user_length < min is
+			 * implied by the test at the end. */
+
+			/* Support for very large requests */
+			if ((descr->flags & IW_DESCR_FLAG_NOMAX) &&
+			   (user_length > descr->max_tokens)) {
+				/* Allow userspace to GET more than max so
+				 * we can support any size GET requests.
+				 * There is still a limit : -ENOMEM. */
+				extra_size = user_length * descr->token_size;
+				/* Note : user_length is originally a __u16,
+				 * and token_size is controlled by us,
+				 * so extra_size won't get negative and
+				 * won't overflow... */
+			}
+		}
+
+		/* Create the kernel buffer */
+		/*    kzalloc ensures NULL-termination for essid_compat */
+		extra = kzalloc(extra_size, GFP_KERNEL);
+		if (extra == NULL)
+			return -ENOMEM;
+
+		/* If it is a SET, get all the extra data in here */
+		if (IW_IS_SET(cmd) && (iwr->u.data.length != 0)) {
+			err = copy_from_user(extra, iwr->u.data.pointer,
+					     iwr->u.data.length *
+					     descr->token_size);
+			if (err) {
+				kfree(extra);
+				return -EFAULT;
+			}
+		}
+
+		/* Call the handler */
+		ret = handler(dev, &info, &(iwr->u), extra);
+
+		iwr->u.data.length += essid_compat;
+
+		/* If we have something to return to the user */
+		if (!ret && IW_IS_GET(cmd)) {
+			/* Check if there is enough buffer up there */
+			if (user_length < iwr->u.data.length) {
+				kfree(extra);
+				return -E2BIG;
+			}
+
+			err = copy_to_user(iwr->u.data.pointer, extra,
+					   iwr->u.data.length *
+					   descr->token_size);
+			if (err)
+				ret =  -EFAULT;
+		}
+
+		/* Generate an event to notify listeners of the change */
+		if ((descr->flags & IW_DESCR_FLAG_EVENT) &&
+		   ((ret == 0) || (ret == -EIWCOMMIT))) {
+			if (descr->flags & IW_DESCR_FLAG_RESTRICT)
+				/* If the event is restricted, don't
+				 * export the payload */
+				wireless_send_event(dev, cmd, &(iwr->u), NULL);
+			else
+				wireless_send_event(dev, cmd, &(iwr->u),
+						    extra);
+		}
+
+		/* Cleanup - I told you it wasn't that long ;-) */
+		kfree(extra);
+	}
+
+	/* Call commit handler if needed and defined */
+	if (ret == -EIWCOMMIT)
+		ret = call_commit_handler(dev);
+
+	/* Here, we will generate the appropriate event if needed */
+
+	return ret;
+}
+
+/* ---------------------------------------------------------------- */
+/*
+ * Wrapper to call a private Wireless Extension handler.
+ * We do various checks and also take care of moving data between
+ * user space and kernel space.
+ * It's not as nice and slimline as the standard wrapper. The cause
+ * is struct iw_priv_args, which was not really designed for the
+ * job we are going here.
+ *
+ * IMPORTANT : This function prevent to set and get data on the same
+ * IOCTL and enforce the SET/GET convention. Not doing it would be
+ * far too hairy...
+ * If you need to set and get data at the same time, please don't use
+ * a iw_handler but process it in your ioctl handler (i.e. use the
+ * old driver API).
+ */
+static int ioctl_private_call(struct net_device *dev, struct ifreq *ifr,
+			      unsigned int cmd, iw_handler handler)
+{
+	struct iwreq *			iwr = (struct iwreq *) ifr;
+	const struct iw_priv_args *	descr = NULL;
+	struct iw_request_info		info;
+	int				extra_size = 0;
+	int				i;
+	int				ret = -EINVAL;
+
+	/* Get the description of the IOCTL */
+	for (i = 0; i < dev->wireless_handlers->num_private_args; i++)
+		if (cmd == dev->wireless_handlers->private_args[i].cmd) {
+			descr = &(dev->wireless_handlers->private_args[i]);
+			break;
+		}
+
+	/* Compute the size of the set/get arguments */
+	if (descr != NULL) {
+		if (IW_IS_SET(cmd)) {
+			int	offset = 0;	/* For sub-ioctls */
+			/* Check for sub-ioctl handler */
+			if (descr->name[0] == '\0')
+				/* Reserve one int for sub-ioctl index */
+				offset = sizeof(__u32);
+
+			/* Size of set arguments */
+			extra_size = get_priv_size(descr->set_args);
+
+			/* Does it fits in iwr ? */
+			if ((descr->set_args & IW_PRIV_SIZE_FIXED) &&
+			   ((extra_size + offset) <= IFNAMSIZ))
+				extra_size = 0;
+		} else {
+			/* Size of get arguments */
+			extra_size = get_priv_size(descr->get_args);
+
+			/* Does it fits in iwr ? */
+			if ((descr->get_args & IW_PRIV_SIZE_FIXED) &&
+			   (extra_size <= IFNAMSIZ))
+				extra_size = 0;
+		}
+	}
+
+	/* Prepare the call */
+	info.cmd = cmd;
+	info.flags = 0;
+
+	/* Check if we have a pointer to user space data or not. */
+	if (extra_size == 0) {
+		/* No extra arguments. Trivial to handle */
+		ret = handler(dev, &info, &(iwr->u), (char *) &(iwr->u));
+	} else {
+		char *	extra;
+		int	err;
+
+		/* Check what user space is giving us */
+		if (IW_IS_SET(cmd)) {
+			/* Check NULL pointer */
+			if ((iwr->u.data.pointer == NULL) &&
+			   (iwr->u.data.length != 0))
+				return -EFAULT;
+
+			/* Does it fits within bounds ? */
+			if (iwr->u.data.length > (descr->set_args &
+						 IW_PRIV_SIZE_MASK))
+				return -E2BIG;
+		} else if (iwr->u.data.pointer == NULL)
+			return -EFAULT;
+
+		/* Always allocate for max space. Easier, and won't last
+		 * long... */
+		extra = kmalloc(extra_size, GFP_KERNEL);
+		if (extra == NULL)
+			return -ENOMEM;
+
+		/* If it is a SET, get all the extra data in here */
+		if (IW_IS_SET(cmd) && (iwr->u.data.length != 0)) {
+			err = copy_from_user(extra, iwr->u.data.pointer,
+					     extra_size);
+			if (err) {
+				kfree(extra);
+				return -EFAULT;
+			}
+		}
+
+		/* Call the handler */
+		ret = handler(dev, &info, &(iwr->u), extra);
+
+		/* If we have something to return to the user */
+		if (!ret && IW_IS_GET(cmd)) {
+
+			/* Adjust for the actual length if it's variable,
+			 * avoid leaking kernel bits outside. */
+			if (!(descr->get_args & IW_PRIV_SIZE_FIXED)) {
+				extra_size = adjust_priv_size(descr->get_args,
+							      &(iwr->u));
+			}
+
+			err = copy_to_user(iwr->u.data.pointer, extra,
+					   extra_size);
+			if (err)
+				ret =  -EFAULT;
+		}
+
+		/* Cleanup - I told you it wasn't that long ;-) */
+		kfree(extra);
+	}
+
+
+	/* Call commit handler if needed and defined */
+	if (ret == -EIWCOMMIT)
+		ret = call_commit_handler(dev);
+
+	return ret;
+}
+
+/* ---------------------------------------------------------------- */
+/*
+ * Main IOCTl dispatcher.
+ * Check the type of IOCTL and call the appropriate wrapper...
+ */
+static int wireless_process_ioctl(struct net *net, struct ifreq *ifr, unsigned int cmd)
+{
+	struct net_device *dev;
+	iw_handler	handler;
+
+	/* Permissions are already checked in dev_ioctl() before calling us.
+	 * The copy_to/from_user() of ifr is also dealt with in there */
+
+	/* Make sure the device exist */
+	if ((dev = __dev_get_by_name(net, ifr->ifr_name)) == NULL)
+		return -ENODEV;
+
+	/* A bunch of special cases, then the generic case...
+	 * Note that 'cmd' is already filtered in dev_ioctl() with
+	 * (cmd >= SIOCIWFIRST && cmd <= SIOCIWLAST) */
+	if (cmd == SIOCGIWSTATS)
+		return ioctl_standard_call(dev, ifr, cmd,
+					   &iw_handler_get_iwstats);
+
+	if (cmd == SIOCGIWPRIV && dev->wireless_handlers)
+		return ioctl_standard_call(dev, ifr, cmd,
+					   &iw_handler_get_private);
+
+	/* Basic check */
+	if (!netif_device_present(dev))
+		return -ENODEV;
+
+	/* New driver API : try to find the handler */
+	handler = get_handler(dev, cmd);
+	if (handler) {
+		/* Standard and private are not the same */
+		if (cmd < SIOCIWFIRSTPRIV)
+			return ioctl_standard_call(dev, ifr, cmd, handler);
+		else
+			return ioctl_private_call(dev, ifr, cmd, handler);
+	}
+	/* Old driver API : call driver ioctl handler */
+	if (dev->do_ioctl)
+		return dev->do_ioctl(dev, ifr, cmd);
+	return -EOPNOTSUPP;
+}
+
+/* entry point from dev ioctl */
+int wext_handle_ioctl(struct net *net, struct ifreq *ifr, unsigned int cmd,
+		      void __user *arg)
+{
+	int ret;
+
+	/* If command is `set a parameter', or
+	 * `get the encoding parameters', check if
+	 * the user has the right to do it */
+	if ((IW_IS_SET(cmd) || cmd == SIOCGIWENCODE || cmd == SIOCGIWENCODEEXT)
+	    && !capable(CAP_NET_ADMIN))
+		return -EPERM;
+
+	dev_load(net, ifr->ifr_name);
+	rtnl_lock();
+	ret = wireless_process_ioctl(net, ifr, cmd);
+	rtnl_unlock();
+	if (IW_IS_GET(cmd) && copy_to_user(arg, ifr, sizeof(struct iwreq)))
+		return -EFAULT;
+	return ret;
+}
+
+/************************* EVENT PROCESSING *************************/
+/*
+ * Process events generated by the wireless layer or the driver.
+ * Most often, the event will be propagated through rtnetlink
+ */
+
+/* ---------------------------------------------------------------- */
+/*
+ * Locking...
+ * ----------
+ *
+ * Thanks to Herbert Xu <herbert@gondor.apana.org.au> for fixing
+ * the locking issue in here and implementing this code !
+ *
+ * The issue : wireless_send_event() is often called in interrupt context,
+ * while the Netlink layer can never be called in interrupt context.
+ * The fully formed RtNetlink events are queued, and then a tasklet is run
+ * to feed those to Netlink.
+ * The skb_queue is interrupt safe, and its lock is not held while calling
+ * Netlink, so there is no possibility of dealock.
+ * Jean II
+ */
+
+static struct sk_buff_head wireless_nlevent_queue;
+
+static int __init wireless_nlevent_init(void)
+{
+	skb_queue_head_init(&wireless_nlevent_queue);
+	return 0;
+}
+
+subsys_initcall(wireless_nlevent_init);
+
+static void wireless_nlevent_process(unsigned long data)
+{
+	struct sk_buff *skb;
+
+	while ((skb = skb_dequeue(&wireless_nlevent_queue)))
+		rtnl_notify(skb, 0, RTNLGRP_LINK, NULL, GFP_ATOMIC);
+}
+
+static DECLARE_TASKLET(wireless_nlevent_tasklet, wireless_nlevent_process, 0);
+
+/* ---------------------------------------------------------------- */
+/*
+ * Fill a rtnetlink message with our event data.
+ * Note that we propage only the specified event and don't dump the
+ * current wireless config. Dumping the wireless config is far too
+ * expensive (for each parameter, the driver need to query the hardware).
+ */
+static int rtnetlink_fill_iwinfo(struct sk_buff *skb, struct net_device *dev,
+				 int type, char *event, int event_len)
+{
+	struct ifinfomsg *r;
+	struct nlmsghdr  *nlh;
+
+	nlh = nlmsg_put(skb, 0, 0, type, sizeof(*r), 0);
+	if (nlh == NULL)
+		return -EMSGSIZE;
+
+	r = nlmsg_data(nlh);
+	r->ifi_family = AF_UNSPEC;
+	r->__ifi_pad = 0;
+	r->ifi_type = dev->type;
+	r->ifi_index = dev->ifindex;
+	r->ifi_flags = dev_get_flags(dev);
+	r->ifi_change = 0;	/* Wireless changes don't affect those flags */
+
+	/* Add the wireless events in the netlink packet */
+	NLA_PUT(skb, IFLA_WIRELESS, event_len, event);
+
+	return nlmsg_end(skb, nlh);
+
+nla_put_failure:
+	nlmsg_cancel(skb, nlh);
+	return -EMSGSIZE;
+}
+
+/* ---------------------------------------------------------------- */
+/*
+ * Create and broadcast and send it on the standard rtnetlink socket
+ * This is a pure clone rtmsg_ifinfo() in net/core/rtnetlink.c
+ * Andrzej Krzysztofowicz mandated that I used a IFLA_XXX field
+ * within a RTM_NEWLINK event.
+ */
+static void rtmsg_iwinfo(struct net_device *dev, char *event, int event_len)
+{
+	struct sk_buff *skb;
+	int err;
+
+	skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_ATOMIC);
+	if (!skb)
+		return;
+
+	err = rtnetlink_fill_iwinfo(skb, dev, RTM_NEWLINK, event, event_len);
+	if (err < 0) {
+		WARN_ON(err == -EMSGSIZE);
+		kfree_skb(skb);
+		return;
+	}
+
+	NETLINK_CB(skb).dst_group = RTNLGRP_LINK;
+	skb_queue_tail(&wireless_nlevent_queue, skb);
+	tasklet_schedule(&wireless_nlevent_tasklet);
+}
+
+/* ---------------------------------------------------------------- */
+/*
+ * Main event dispatcher. Called from other parts and drivers.
+ * Send the event on the appropriate channels.
+ * May be called from interrupt context.
+ */
+void wireless_send_event(struct net_device *	dev,
+			 unsigned int		cmd,
+			 union iwreq_data *	wrqu,
+			 char *			extra)
+{
+	const struct iw_ioctl_description *	descr = NULL;
+	int extra_len = 0;
+	struct iw_event  *event;		/* Mallocated whole event */
+	int event_len;				/* Its size */
+	int hdr_len;				/* Size of the event header */
+	int wrqu_off = 0;			/* Offset in wrqu */
+	/* Don't "optimise" the following variable, it will crash */
+	unsigned	cmd_index;		/* *MUST* be unsigned */
+
+	/* Get the description of the Event */
+	if (cmd <= SIOCIWLAST) {
+		cmd_index = cmd - SIOCIWFIRST;
+		if (cmd_index < standard_ioctl_num)
+			descr = &(standard_ioctl[cmd_index]);
+	} else {
+		cmd_index = cmd - IWEVFIRST;
+		if (cmd_index < standard_event_num)
+			descr = &(standard_event[cmd_index]);
+	}
+	/* Don't accept unknown events */
+	if (descr == NULL) {
+		/* Note : we don't return an error to the driver, because
+		 * the driver would not know what to do about it. It can't
+		 * return an error to the user, because the event is not
+		 * initiated by a user request.
+		 * The best the driver could do is to log an error message.
+		 * We will do it ourselves instead...
+		 */
+		printk(KERN_ERR "%s (WE) : Invalid/Unknown Wireless Event (0x%04X)\n",
+		       dev->name, cmd);
+		return;
+	}
+
+	/* Check extra parameters and set extra_len */
+	if (descr->header_type == IW_HEADER_TYPE_POINT) {
+		/* Check if number of token fits within bounds */
+		if (wrqu->data.length > descr->max_tokens) {
+			printk(KERN_ERR "%s (WE) : Wireless Event too big (%d)\n", dev->name, wrqu->data.length);
+			return;
+		}
+		if (wrqu->data.length < descr->min_tokens) {
+			printk(KERN_ERR "%s (WE) : Wireless Event too small (%d)\n", dev->name, wrqu->data.length);
+			return;
+		}
+		/* Calculate extra_len - extra is NULL for restricted events */
+		if (extra != NULL)
+			extra_len = wrqu->data.length * descr->token_size;
+		/* Always at an offset in wrqu */
+		wrqu_off = IW_EV_POINT_OFF;
+	}
+
+	/* Total length of the event */
+	hdr_len = event_type_size[descr->header_type];
+	event_len = hdr_len + extra_len;
+
+	/* Create temporary buffer to hold the event */
+	event = kmalloc(event_len, GFP_ATOMIC);
+	if (event == NULL)
+		return;
+
+	/* Fill event */
+	event->len = event_len;
+	event->cmd = cmd;
+	memcpy(&event->u, ((char *) wrqu) + wrqu_off, hdr_len - IW_EV_LCP_LEN);
+	if (extra)
+		memcpy(((char *) event) + hdr_len, extra, extra_len);
+
+	/* Send via the RtNetlink event channel */
+	rtmsg_iwinfo(dev, (char *) event, event_len);
+
+	/* Cleanup */
+	kfree(event);
+
+	return;		/* Always success, I guess ;-) */
+}
+EXPORT_SYMBOL(wireless_send_event);
+
+/********************** ENHANCED IWSPY SUPPORT **********************/
+/*
+ * In the old days, the driver was handling spy support all by itself.
+ * Now, the driver can delegate this task to Wireless Extensions.
+ * It needs to use those standard spy iw_handler in struct iw_handler_def,
+ * push data to us via wireless_spy_update() and include struct iw_spy_data
+ * in its private part (and export it in net_device->wireless_data->spy_data).
+ * One of the main advantage of centralising spy support here is that
+ * it becomes much easier to improve and extend it without having to touch
+ * the drivers. One example is the addition of the Spy-Threshold events.
+ */
+
+/* ---------------------------------------------------------------- */
+/*
+ * Return the pointer to the spy data in the driver.
+ * Because this is called on the Rx path via wireless_spy_update(),
+ * we want it to be efficient...
+ */
+static inline struct iw_spy_data *get_spydata(struct net_device *dev)
+{
+	/* This is the new way */
+	if (dev->wireless_data)
+		return dev->wireless_data->spy_data;
+	return NULL;
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * Standard Wireless Handler : set Spy List
+ */
+int iw_handler_set_spy(struct net_device *	dev,
+		       struct iw_request_info *	info,
+		       union iwreq_data *	wrqu,
+		       char *			extra)
+{
+	struct iw_spy_data *	spydata = get_spydata(dev);
+	struct sockaddr *	address = (struct sockaddr *) extra;
+
+	/* Make sure driver is not buggy or using the old API */
+	if (!spydata)
+		return -EOPNOTSUPP;
+
+	/* Disable spy collection while we copy the addresses.
+	 * While we copy addresses, any call to wireless_spy_update()
+	 * will NOP. This is OK, as anyway the addresses are changing. */
+	spydata->spy_number = 0;
+
+	/* We want to operate without locking, because wireless_spy_update()
+	 * most likely will happen in the interrupt handler, and therefore
+	 * have its own locking constraints and needs performance.
+	 * The rtnl_lock() make sure we don't race with the other iw_handlers.
+	 * This make sure wireless_spy_update() "see" that the spy list
+	 * is temporarily disabled. */
+	smp_wmb();
+
+	/* Are there are addresses to copy? */
+	if (wrqu->data.length > 0) {
+		int i;
+
+		/* Copy addresses */
+		for (i = 0; i < wrqu->data.length; i++)
+			memcpy(spydata->spy_address[i], address[i].sa_data,
+			       ETH_ALEN);
+		/* Reset stats */
+		memset(spydata->spy_stat, 0,
+		       sizeof(struct iw_quality) * IW_MAX_SPY);
+	}
+
+	/* Make sure above is updated before re-enabling */
+	smp_wmb();
+
+	/* Enable addresses */
+	spydata->spy_number = wrqu->data.length;
+
+	return 0;
+}
+EXPORT_SYMBOL(iw_handler_set_spy);
+
+/*------------------------------------------------------------------*/
+/*
+ * Standard Wireless Handler : get Spy List
+ */
+int iw_handler_get_spy(struct net_device *	dev,
+		       struct iw_request_info *	info,
+		       union iwreq_data *	wrqu,
+		       char *			extra)
+{
+	struct iw_spy_data *	spydata = get_spydata(dev);
+	struct sockaddr *	address = (struct sockaddr *) extra;
+	int			i;
+
+	/* Make sure driver is not buggy or using the old API */
+	if (!spydata)
+		return -EOPNOTSUPP;
+
+	wrqu->data.length = spydata->spy_number;
+
+	/* Copy addresses. */
+	for (i = 0; i < spydata->spy_number; i++) 	{
+		memcpy(address[i].sa_data, spydata->spy_address[i], ETH_ALEN);
+		address[i].sa_family = AF_UNIX;
+	}
+	/* Copy stats to the user buffer (just after). */
+	if (spydata->spy_number > 0)
+		memcpy(extra  + (sizeof(struct sockaddr) *spydata->spy_number),
+		       spydata->spy_stat,
+		       sizeof(struct iw_quality) * spydata->spy_number);
+	/* Reset updated flags. */
+	for (i = 0; i < spydata->spy_number; i++)
+		spydata->spy_stat[i].updated &= ~IW_QUAL_ALL_UPDATED;
+	return 0;
+}
+EXPORT_SYMBOL(iw_handler_get_spy);
+
+/*------------------------------------------------------------------*/
+/*
+ * Standard Wireless Handler : set spy threshold
+ */
+int iw_handler_set_thrspy(struct net_device *	dev,
+			  struct iw_request_info *info,
+			  union iwreq_data *	wrqu,
+			  char *		extra)
+{
+	struct iw_spy_data *	spydata = get_spydata(dev);
+	struct iw_thrspy *	threshold = (struct iw_thrspy *) extra;
+
+	/* Make sure driver is not buggy or using the old API */
+	if (!spydata)
+		return -EOPNOTSUPP;
+
+	/* Just do it */
+	memcpy(&(spydata->spy_thr_low), &(threshold->low),
+	       2 * sizeof(struct iw_quality));
+
+	/* Clear flag */
+	memset(spydata->spy_thr_under, '\0', sizeof(spydata->spy_thr_under));
+
+	return 0;
+}
+EXPORT_SYMBOL(iw_handler_set_thrspy);
+
+/*------------------------------------------------------------------*/
+/*
+ * Standard Wireless Handler : get spy threshold
+ */
+int iw_handler_get_thrspy(struct net_device *	dev,
+			  struct iw_request_info *info,
+			  union iwreq_data *	wrqu,
+			  char *		extra)
+{
+	struct iw_spy_data *	spydata = get_spydata(dev);
+	struct iw_thrspy *	threshold = (struct iw_thrspy *) extra;
+
+	/* Make sure driver is not buggy or using the old API */
+	if (!spydata)
+		return -EOPNOTSUPP;
+
+	/* Just do it */
+	memcpy(&(threshold->low), &(spydata->spy_thr_low),
+	       2 * sizeof(struct iw_quality));
+
+	return 0;
+}
+EXPORT_SYMBOL(iw_handler_get_thrspy);
+
+/*------------------------------------------------------------------*/
+/*
+ * Prepare and send a Spy Threshold event
+ */
+static void iw_send_thrspy_event(struct net_device *	dev,
+				 struct iw_spy_data *	spydata,
+				 unsigned char *	address,
+				 struct iw_quality *	wstats)
+{
+	union iwreq_data	wrqu;
+	struct iw_thrspy	threshold;
+
+	/* Init */
+	wrqu.data.length = 1;
+	wrqu.data.flags = 0;
+	/* Copy address */
+	memcpy(threshold.addr.sa_data, address, ETH_ALEN);
+	threshold.addr.sa_family = ARPHRD_ETHER;
+	/* Copy stats */
+	memcpy(&(threshold.qual), wstats, sizeof(struct iw_quality));
+	/* Copy also thresholds */
+	memcpy(&(threshold.low), &(spydata->spy_thr_low),
+	       2 * sizeof(struct iw_quality));
+
+	/* Send event to user space */
+	wireless_send_event(dev, SIOCGIWTHRSPY, &wrqu, (char *) &threshold);
+}
+
+/* ---------------------------------------------------------------- */
+/*
+ * Call for the driver to update the spy data.
+ * For now, the spy data is a simple array. As the size of the array is
+ * small, this is good enough. If we wanted to support larger number of
+ * spy addresses, we should use something more efficient...
+ */
+void wireless_spy_update(struct net_device *	dev,
+			 unsigned char *	address,
+			 struct iw_quality *	wstats)
+{
+	struct iw_spy_data *	spydata = get_spydata(dev);
+	int			i;
+	int			match = -1;
+
+	/* Make sure driver is not buggy or using the old API */
+	if (!spydata)
+		return;
+
+	/* Update all records that match */
+	for (i = 0; i < spydata->spy_number; i++)
+		if (!compare_ether_addr(address, spydata->spy_address[i])) {
+			memcpy(&(spydata->spy_stat[i]), wstats,
+			       sizeof(struct iw_quality));
+			match = i;
+		}
+
+	/* Generate an event if we cross the spy threshold.
+	 * To avoid event storms, we have a simple hysteresis : we generate
+	 * event only when we go under the low threshold or above the
+	 * high threshold. */
+	if (match >= 0) {
+		if (spydata->spy_thr_under[match]) {
+			if (wstats->level > spydata->spy_thr_high.level) {
+				spydata->spy_thr_under[match] = 0;
+				iw_send_thrspy_event(dev, spydata,
+						     address, wstats);
+			}
+		} else {
+			if (wstats->level < spydata->spy_thr_low.level) {
+				spydata->spy_thr_under[match] = 1;
+				iw_send_thrspy_event(dev, spydata,
+						     address, wstats);
+			}
+		}
+	}
+}
+EXPORT_SYMBOL(wireless_spy_update);