summary refs log tree commit diff
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2008-07-14 20:40:34 -0700
committerDavid S. Miller <davem@davemloft.net>2008-07-14 20:40:34 -0700
commitfc943b12e48f9341bce48c2fadf094cc721aab93 (patch)
tree8c3244d7f5fae4edbfe0a5103789b0bc5c64f478
parent72d9794f444734af56ef12833b496326643e2964 (diff)
parent4c9adafff7d910f142fe44fae37ed12c6b99f20f (diff)
downloadlinux-fc943b12e48f9341bce48c2fadf094cc721aab93.tar.gz
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-next-2.6
-rw-r--r--Documentation/feature-removal-schedule.txt10
-rw-r--r--drivers/net/wireless/ath5k/base.c13
-rw-r--r--drivers/net/wireless/b43/main.c48
-rw-r--r--drivers/net/wireless/b43/xmit.c3
-rw-r--r--drivers/net/wireless/b43legacy/main.c45
-rw-r--r--drivers/net/wireless/b43legacy/xmit.c3
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-3945-led.c146
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-3945-led.h2
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-3945.c50
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-3945.h20
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-4965-hw.h1
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-4965-rs.c2
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-4965.c42
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-5000-hw.h1
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-5000.c48
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-commands.h30
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-core.c2
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-core.h5
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-dev.h27
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-led.c207
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-led.h5
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-rx.c37
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-scan.c103
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-tx.c8
-rw-r--r--drivers/net/wireless/iwlwifi/iwl3945-base.c145
-rw-r--r--drivers/net/wireless/iwlwifi/iwl4965-base.c108
-rw-r--r--drivers/net/wireless/mac80211_hwsim.c2
-rw-r--r--drivers/net/wireless/rt2x00/rt2400pci.c89
-rw-r--r--drivers/net/wireless/rt2x00/rt2500pci.c90
-rw-r--r--drivers/net/wireless/rt2x00/rt2500usb.c154
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00.h37
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00config.c2
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00dev.c9
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00firmware.c8
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00lib.h8
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00mac.c40
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00queue.c67
-rw-r--r--drivers/net/wireless/rt2x00/rt61pci.c103
-rw-r--r--drivers/net/wireless/rt2x00/rt73usb.c115
-rw-r--r--drivers/net/wireless/rtl8187_dev.c23
-rw-r--r--drivers/net/wireless/rtl8187_rtl8225.c21
-rw-r--r--drivers/net/wireless/rtl8187_rtl8225.h15
-rw-r--r--drivers/net/wireless/zd1211rw/zd_mac.c22
-rw-r--r--include/linux/ssb/ssb.h1
-rw-r--r--include/net/mac80211.h73
-rw-r--r--net/core/net-sysfs.c4
-rw-r--r--net/mac80211/cfg.c36
-rw-r--r--net/mac80211/debugfs.c15
-rw-r--r--net/mac80211/debugfs_netdev.c48
-rw-r--r--net/mac80211/debugfs_netdev.h5
-rw-r--r--net/mac80211/ieee80211_i.h67
-rw-r--r--net/mac80211/iface.c392
-rw-r--r--net/mac80211/main.c171
-rw-r--r--net/mac80211/mlme.c172
-rw-r--r--net/mac80211/rc80211_pid_algo.c8
-rw-r--r--net/mac80211/rx.c38
-rw-r--r--net/mac80211/sta_info.c29
-rw-r--r--net/mac80211/sta_info.h1
-rw-r--r--net/mac80211/tx.c126
-rw-r--r--net/mac80211/util.c4
-rw-r--r--net/mac80211/wext.c65
-rw-r--r--net/wireless/Kconfig11
62 files changed, 1458 insertions, 1724 deletions
diff --git a/Documentation/feature-removal-schedule.txt b/Documentation/feature-removal-schedule.txt
index 8319c462c9f0..db300e09c9ac 100644
--- a/Documentation/feature-removal-schedule.txt
+++ b/Documentation/feature-removal-schedule.txt
@@ -333,3 +333,13 @@ Why:	This option was introduced just to allow older lm-sensors userspace
 	to keep working over the upgrade to 2.6.26. At the scheduled time of
 	removal fixed lm-sensors (2.x or 3.x) should be readily available.
 Who:	Rene Herman <rene.herman@gmail.com>
+
+---------------------------
+
+What:	Code that is now under CONFIG_WIRELESS_EXT_SYSFS
+	(in net/core/net-sysfs.c)
+When:	After the only user (hal) has seen a release with the patches
+	for enough time, probably some time in 2010.
+Why:	Over 1K .text/.data size reduction, data is available in other
+	ways (ioctls)
+Who:	Johannes Berg <johannes@sipsolutions.net>
diff --git a/drivers/net/wireless/ath5k/base.c b/drivers/net/wireless/ath5k/base.c
index a43e9b25169b..217d506527a9 100644
--- a/drivers/net/wireless/ath5k/base.c
+++ b/drivers/net/wireless/ath5k/base.c
@@ -207,7 +207,6 @@ static struct ieee80211_ops ath5k_hw_ops = {
 	.get_tx_stats 	= ath5k_get_tx_stats,
 	.get_tsf 	= ath5k_get_tsf,
 	.reset_tsf 	= ath5k_reset_tsf,
-	.beacon_update 	= ath5k_beacon_update,
 };
 
 /*
@@ -2785,6 +2784,18 @@ ath5k_config_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
 		 * a clean way of letting us retrieve this yet. */
 		ath5k_hw_set_associd(ah, ah->ah_bssid, 0);
 	}
+
+	if (conf->changed & IEEE80211_IFCC_BEACON &&
+	    vif->type == IEEE80211_IF_TYPE_IBSS) {
+		struct sk_buff *beacon = ieee80211_beacon_get(hw, vif);
+		if (!beacon) {
+			ret = -ENOMEM;
+			goto unlock;
+		}
+		/* call old handler for now */
+		ath5k_beacon_update(hw, beacon);
+	}
+
 	mutex_unlock(&sc->lock);
 
 	return ath5k_reset(hw);
diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c
index 9d2eb273b726..381dbd33dfc2 100644
--- a/drivers/net/wireless/b43/main.c
+++ b/drivers/net/wireless/b43/main.c
@@ -1675,14 +1675,24 @@ static void b43_beacon_update_trigger_work(struct work_struct *work)
 
 /* 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)
+static void b43_update_templates(struct b43_wl *wl)
 {
+	struct sk_buff *beacon;
+
 	/* 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. */
 
+	/* 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(wl->hw, wl->vif);
+	if (unlikely(!beacon))
+		return;
+
 	if (wl->current_beacon)
 		dev_kfree_skb_any(wl->current_beacon);
 	wl->current_beacon = beacon;
@@ -3645,10 +3655,14 @@ static int b43_op_config_interface(struct ieee80211_hw *hw,
 	if (b43_status(dev) >= B43_STAT_INITIALIZED) {
 		if (b43_is_mode(wl, IEEE80211_IF_TYPE_AP) ||
 		    b43_is_mode(wl, IEEE80211_IF_TYPE_MESH_POINT)) {
-			B43_WARN_ON(conf->type != wl->if_type);
-			b43_set_ssid(dev, conf->ssid, conf->ssid_len);
-			if (conf->beacon)
-				b43_update_templates(wl, conf->beacon);
+			B43_WARN_ON(vif->type != wl->if_type);
+			if (conf->changed & IEEE80211_IFCC_SSID)
+				b43_set_ssid(dev, conf->ssid, conf->ssid_len);
+			if (conf->changed & IEEE80211_IFCC_BEACON)
+				b43_update_templates(wl);
+		} else if (b43_is_mode(wl, IEEE80211_IF_TYPE_IBSS)) {
+			if (conf->changed & IEEE80211_IFCC_BEACON)
+				b43_update_templates(wl);
 		}
 		b43_write_mac_bssid_templates(dev);
 	}
@@ -4336,31 +4350,10 @@ out_unlock:
 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);
-	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 b43_wl *wl = hw_to_b43_wl(hw);
 	unsigned long flags;
 
 	spin_lock_irqsave(&wl->irq_lock, flags);
-	b43_update_templates(wl, beacon);
+	b43_update_templates(wl);
 	spin_unlock_irqrestore(&wl->irq_lock, flags);
 
 	return 0;
@@ -4391,7 +4384,6 @@ static const struct ieee80211_ops b43_hw_ops = {
 	.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,
 	.sta_notify		= b43_op_sta_notify,
 };
 
diff --git a/drivers/net/wireless/b43/xmit.c b/drivers/net/wireless/b43/xmit.c
index bf6f6c1ed4cf..8d54502222a6 100644
--- a/drivers/net/wireless/b43/xmit.c
+++ b/drivers/net/wireless/b43/xmit.c
@@ -317,7 +317,8 @@ int b43_generate_txhdr(struct b43_wldev *dev,
 	/* MAC control */
 	if (!(info->flags & IEEE80211_TX_CTL_NO_ACK))
 		mac_ctl |= B43_TXH_MAC_ACK;
-	if (!ieee80211_is_pspoll(fctl))
+	/* use hardware sequence counter as the non-TID counter */
+	if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ)
 		mac_ctl |= B43_TXH_MAC_HWSEQ;
 	if (info->flags & IEEE80211_TX_CTL_FIRST_FRAGMENT)
 		mac_ctl |= B43_TXH_MAC_STMSDU;
diff --git a/drivers/net/wireless/b43legacy/main.c b/drivers/net/wireless/b43legacy/main.c
index 069157eea05c..a1b8bf3ee732 100644
--- a/drivers/net/wireless/b43legacy/main.c
+++ b/drivers/net/wireless/b43legacy/main.c
@@ -1138,14 +1138,22 @@ static void b43legacy_write_probe_resp_template(struct b43legacy_wldev *dev,
 
 /* Asynchronously update the packet templates in template RAM.
  * Locking: Requires wl->irq_lock to be locked. */
-static void b43legacy_update_templates(struct b43legacy_wl *wl,
-				       struct sk_buff *beacon)
+static void b43legacy_update_templates(struct b43legacy_wl *wl)
 {
+	struct sk_buff *beacon;
 	/* 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. */
 
+	/* 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(wl->hw, wl->vif);
+	if (unlikely(!beacon))
+		return;
+
 	if (wl->current_beacon)
 		dev_kfree_skb_any(wl->current_beacon);
 	wl->current_beacon = beacon;
@@ -2727,10 +2735,13 @@ static int b43legacy_op_config_interface(struct ieee80211_hw *hw,
 		memset(wl->bssid, 0, ETH_ALEN);
 	if (b43legacy_status(dev) >= B43legacy_STAT_INITIALIZED) {
 		if (b43legacy_is_mode(wl, IEEE80211_IF_TYPE_AP)) {
-			B43legacy_WARN_ON(conf->type != IEEE80211_IF_TYPE_AP);
+			B43legacy_WARN_ON(vif->type != IEEE80211_IF_TYPE_AP);
 			b43legacy_set_ssid(dev, conf->ssid, conf->ssid_len);
-			if (conf->beacon)
-				b43legacy_update_templates(wl, conf->beacon);
+			if (conf->changed & IEEE80211_IFCC_BEACON)
+				b43legacy_update_templates(wl);
+		} else if (b43legacy_is_mode(wl, IEEE80211_IF_TYPE_IBSS)) {
+			if (conf->changed & IEEE80211_IFCC_BEACON)
+				b43legacy_update_templates(wl);
 		}
 		b43legacy_write_mac_bssid_templates(dev);
 	}
@@ -3396,31 +3407,10 @@ static int b43legacy_op_beacon_set_tim(struct ieee80211_hw *hw,
 				       int aid, int set)
 {
 	struct b43legacy_wl *wl = hw_to_b43legacy_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);
-	if (unlikely(!beacon))
-		return -ENOMEM;
-	spin_lock_irqsave(&wl->irq_lock, flags);
-	b43legacy_update_templates(wl, beacon);
-	spin_unlock_irqrestore(&wl->irq_lock, flags);
-
-	return 0;
-}
-
-static int b43legacy_op_ibss_beacon_update(struct ieee80211_hw *hw,
-					   struct sk_buff *beacon)
-{
-	struct b43legacy_wl *wl = hw_to_b43legacy_wl(hw);
 	unsigned long flags;
 
 	spin_lock_irqsave(&wl->irq_lock, flags);
-	b43legacy_update_templates(wl, beacon);
+	b43legacy_update_templates(wl);
 	spin_unlock_irqrestore(&wl->irq_lock, flags);
 
 	return 0;
@@ -3440,7 +3430,6 @@ static const struct ieee80211_ops b43legacy_hw_ops = {
 	.stop			= b43legacy_op_stop,
 	.set_retry_limit	= b43legacy_op_set_retry_limit,
 	.set_tim		= b43legacy_op_beacon_set_tim,
-	.beacon_update		= b43legacy_op_ibss_beacon_update,
 };
 
 /* Hard-reset the chip. Do not call this directly.
diff --git a/drivers/net/wireless/b43legacy/xmit.c b/drivers/net/wireless/b43legacy/xmit.c
index a3540787eb50..e969ed8d412d 100644
--- a/drivers/net/wireless/b43legacy/xmit.c
+++ b/drivers/net/wireless/b43legacy/xmit.c
@@ -295,8 +295,7 @@ static int generate_txhdr_fw3(struct b43legacy_wldev *dev,
 	/* MAC control */
 	if (!(info->flags & IEEE80211_TX_CTL_NO_ACK))
 		mac_ctl |= B43legacy_TX4_MAC_ACK;
-	if (!(((fctl & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_CTL) &&
-	      ((fctl & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_PSPOLL)))
+	if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ)
 		mac_ctl |= B43legacy_TX4_MAC_HWSEQ;
 	if (info->flags & IEEE80211_TX_CTL_FIRST_FRAGMENT)
 		mac_ctl |= B43legacy_TX4_MAC_STMSDU;
diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-led.c b/drivers/net/wireless/iwlwifi/iwl-3945-led.c
index 8b1528e52d43..6be1fe13fa57 100644
--- a/drivers/net/wireless/iwlwifi/iwl-3945-led.c
+++ b/drivers/net/wireless/iwlwifi/iwl-3945-led.c
@@ -42,14 +42,11 @@
 #include "iwl-3945.h"
 #include "iwl-helpers.h"
 
-#define IWL_1MB_RATE (128 * 1024)
-#define IWL_LED_THRESHOLD (16)
-#define IWL_MAX_BLINK_TBL (10)
 
 static const struct {
 	u16 brightness;
 	u8 on_time;
-	u8 of_time;
+	u8 off_time;
 } blink_tbl[] =
 {
 	{300, 25, 25},
@@ -61,9 +58,16 @@ static const struct {
 	{15, 95, 95 },
 	{10, 110, 110},
 	{5, 130, 130},
-	{0, 167, 167}
+	{0, 167, 167},
+	/*SOLID_ON*/
+	{-1, IWL_LED_SOLID, 0}
 };
 
+#define IWL_1MB_RATE (128 * 1024)
+#define IWL_LED_THRESHOLD (16)
+#define IWL_MAX_BLINK_TBL (ARRAY_SIZE(blink_tbl) - 1) /*Exclude Solid on*/
+#define IWL_SOLID_BLINK_IDX (ARRAY_SIZE(blink_tbl) - 1)
+
 static int iwl3945_led_cmd_callback(struct iwl3945_priv *priv,
 				    struct iwl3945_cmd *cmd,
 				    struct sk_buff *skb)
@@ -71,6 +75,10 @@ static int iwl3945_led_cmd_callback(struct iwl3945_priv *priv,
 	return 1;
 }
 
+static inline int iwl3945_brightness_to_idx(enum led_brightness brightness)
+{
+	return fls(0x000000FF & (u32)brightness);
+}
 
 /* Send led command */
 static int iwl_send_led_cmd(struct iwl3945_priv *priv,
@@ -81,49 +89,45 @@ static int iwl_send_led_cmd(struct iwl3945_priv *priv,
 		.len = sizeof(struct iwl3945_led_cmd),
 		.data = led_cmd,
 		.meta.flags = CMD_ASYNC,
-		.meta.u.callback = iwl3945_led_cmd_callback
+		.meta.u.callback = iwl3945_led_cmd_callback,
 	};
 
 	return iwl3945_send_cmd(priv, &cmd);
 }
 
 
+
 /* Set led on command */
-static int iwl3945_led_on(struct iwl3945_priv *priv, int led_id)
+static int iwl3945_led_pattern(struct iwl3945_priv *priv, int led_id,
+			       unsigned int idx)
 {
 	struct iwl3945_led_cmd led_cmd = {
 		.id = led_id,
-		.on = IWL_LED_SOLID,
-		.off = 0,
 		.interval = IWL_DEF_LED_INTRVL
 	};
+
+	BUG_ON(idx > IWL_MAX_BLINK_TBL);
+
+	led_cmd.on = blink_tbl[idx].on_time;
+	led_cmd.off = blink_tbl[idx].off_time;
+
 	return iwl_send_led_cmd(priv, &led_cmd);
 }
 
+
+#if 1
 /* Set led on command */
-static int iwl3945_led_pattern(struct iwl3945_priv *priv, int led_id,
-			       enum led_brightness brightness)
+static int iwl3945_led_on(struct iwl3945_priv *priv, int led_id)
 {
 	struct iwl3945_led_cmd led_cmd = {
 		.id = led_id,
-		.on = brightness,
-		.off = brightness,
+		.on = IWL_LED_SOLID,
+		.off = 0,
 		.interval = IWL_DEF_LED_INTRVL
 	};
-	if (brightness == LED_FULL) {
-		led_cmd.on = IWL_LED_SOLID;
-		led_cmd.off = 0;
-	}
 	return iwl_send_led_cmd(priv, &led_cmd);
 }
 
-/* Set led register off */
-static int iwl3945_led_on_reg(struct iwl3945_priv *priv, int led_id)
-{
-	IWL_DEBUG_LED("led on %d\n", led_id);
-	return iwl3945_led_on(priv, led_id);
-}
-
 /* Set led off command */
 static int iwl3945_led_off(struct iwl3945_priv *priv, int led_id)
 {
@@ -136,27 +140,7 @@ static int iwl3945_led_off(struct iwl3945_priv *priv, int led_id)
 	IWL_DEBUG_LED("led off %d\n", led_id);
 	return iwl_send_led_cmd(priv, &led_cmd);
 }
-
-/* Set led register off */
-static int iwl3945_led_off_reg(struct iwl3945_priv *priv, int led_id)
-{
-	iwl3945_led_off(priv, led_id);
-	return 0;
-}
-
-/* Set led blink command */
-static int iwl3945_led_not_solid(struct iwl3945_priv *priv, int led_id,
-			       u8 brightness)
-{
-	struct iwl3945_led_cmd led_cmd = {
-		.id = led_id,
-		.on = brightness,
-		.off = brightness,
-		.interval = IWL_DEF_LED_INTRVL
-	};
-
-	return iwl_send_led_cmd(priv, &led_cmd);
-}
+#endif
 
 
 /*
@@ -206,8 +190,10 @@ static void iwl3945_led_brightness_set(struct led_classdev *led_cdev,
 			led->led_off(priv, IWL_LED_LINK);
 		break;
 	default:
-		if (led->led_pattern)
-			led->led_pattern(priv, IWL_LED_LINK, brightness);
+		if (led->led_pattern) {
+			int idx = iwl3945_brightness_to_idx(brightness);
+			led->led_pattern(priv, IWL_LED_LINK, idx);
+		}
 		break;
 	}
 }
@@ -252,24 +238,20 @@ static int iwl3945_led_register_led(struct iwl3945_priv *priv,
 static inline u8 get_blink_rate(struct iwl3945_priv *priv)
 {
 	int index;
-	u8 blink_rate;
-
-	if (priv->rxtxpackets < IWL_LED_THRESHOLD)
-		index = 10;
-	else {
-		for (index = 0; index < IWL_MAX_BLINK_TBL; index++) {
-			if (priv->rxtxpackets > (blink_tbl[index].brightness *
-						 IWL_1MB_RATE))
-				break;
-		}
-	}
-	/* if 0 frame is transfered */
-	if ((index == IWL_MAX_BLINK_TBL) || !priv->allow_blinking)
-		blink_rate = IWL_LED_SOLID;
-	else
-		blink_rate = blink_tbl[index].on_time;
+	u64 current_tpt = priv->rxtxpackets;
+	s64 tpt = current_tpt - priv->led_tpt;
 
-	return blink_rate;
+	if (tpt < 0)
+		tpt = -tpt;
+	priv->led_tpt = current_tpt;
+
+	if (!priv->allow_blinking)
+		index = IWL_MAX_BLINK_TBL;
+	else
+		for (index = 0; index < IWL_MAX_BLINK_TBL; index++)
+			if (tpt > (blink_tbl[index].brightness * IWL_1MB_RATE))
+				break;
+	return index;
 }
 
 static inline int is_rf_kill(struct iwl3945_priv *priv)
@@ -285,7 +267,7 @@ static inline int is_rf_kill(struct iwl3945_priv *priv)
  */
 void iwl3945_led_background(struct iwl3945_priv *priv)
 {
-	u8 blink_rate;
+	u8 blink_idx;
 
 	if (test_bit(STATUS_EXIT_PENDING, &priv->status)) {
 		priv->last_blink_time = 0;
@@ -298,9 +280,10 @@ void iwl3945_led_background(struct iwl3945_priv *priv)
 
 	if (!priv->allow_blinking) {
 		priv->last_blink_time = 0;
-		if (priv->last_blink_rate != IWL_LED_SOLID) {
-			priv->last_blink_rate = IWL_LED_SOLID;
-			iwl3945_led_on(priv, IWL_LED_LINK);
+		if (priv->last_blink_rate != IWL_SOLID_BLINK_IDX) {
+			priv->last_blink_rate = IWL_SOLID_BLINK_IDX;
+			iwl3945_led_pattern(priv, IWL_LED_LINK,
+					    IWL_SOLID_BLINK_IDX);
 		}
 		return;
 	}
@@ -309,21 +292,14 @@ void iwl3945_led_background(struct iwl3945_priv *priv)
 			msecs_to_jiffies(1000)))
 		return;
 
-	blink_rate = get_blink_rate(priv);
+	blink_idx = get_blink_rate(priv);
 
 	/* call only if blink rate change */
-	if (blink_rate != priv->last_blink_rate) {
-		if (blink_rate != IWL_LED_SOLID) {
-			priv->last_blink_time = jiffies +
-						msecs_to_jiffies(1000);
-			iwl3945_led_not_solid(priv, IWL_LED_LINK, blink_rate);
-		} else {
-			priv->last_blink_time = 0;
-			iwl3945_led_on(priv, IWL_LED_LINK);
-		}
-	}
+	if (blink_idx != priv->last_blink_rate)
+		iwl3945_led_pattern(priv, IWL_LED_LINK, blink_idx);
 
-	priv->last_blink_rate = blink_rate;
+	priv->last_blink_time = jiffies;
+	priv->last_blink_rate = blink_idx;
 	priv->rxtxpackets = 0;
 }
 
@@ -337,6 +313,7 @@ int iwl3945_led_register(struct iwl3945_priv *priv)
 
 	priv->last_blink_rate = 0;
 	priv->rxtxpackets = 0;
+	priv->led_tpt = 0;
 	priv->last_blink_time = 0;
 	priv->allow_blinking = 0;
 
@@ -344,8 +321,8 @@ int iwl3945_led_register(struct iwl3945_priv *priv)
 	snprintf(name, sizeof(name), "iwl-%s:radio",
 		 wiphy_name(priv->hw->wiphy));
 
-	priv->led[IWL_LED_TRG_RADIO].led_on = iwl3945_led_on_reg;
-	priv->led[IWL_LED_TRG_RADIO].led_off = iwl3945_led_off_reg;
+	priv->led[IWL_LED_TRG_RADIO].led_on = iwl3945_led_on;
+	priv->led[IWL_LED_TRG_RADIO].led_off = iwl3945_led_off;
 	priv->led[IWL_LED_TRG_RADIO].led_pattern = NULL;
 
 	ret = iwl3945_led_register_led(priv,
@@ -364,8 +341,8 @@ int iwl3945_led_register(struct iwl3945_priv *priv)
 				   IWL_LED_TRG_ASSOC, 0,
 				   name, trigger);
 	/* for assoc always turn led on */
-	priv->led[IWL_LED_TRG_ASSOC].led_on = iwl3945_led_on_reg;
-	priv->led[IWL_LED_TRG_ASSOC].led_off = iwl3945_led_on_reg;
+	priv->led[IWL_LED_TRG_ASSOC].led_on = iwl3945_led_on;
+	priv->led[IWL_LED_TRG_ASSOC].led_off = iwl3945_led_on;
 	priv->led[IWL_LED_TRG_ASSOC].led_pattern = NULL;
 
 	if (ret)
@@ -391,6 +368,7 @@ int iwl3945_led_register(struct iwl3945_priv *priv)
 	trigger = ieee80211_get_tx_led_name(priv->hw);
 	snprintf(name, sizeof(name), "iwl-%s:TX",
 		 wiphy_name(priv->hw->wiphy));
+
 	ret = iwl3945_led_register_led(priv,
 				   &priv->led[IWL_LED_TRG_TX],
 				   IWL_LED_TRG_TX, 0,
diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-led.h b/drivers/net/wireless/iwlwifi/iwl-3945-led.h
index b1d2f6b8b259..47b7e0bac802 100644
--- a/drivers/net/wireless/iwlwifi/iwl-3945-led.h
+++ b/drivers/net/wireless/iwlwifi/iwl-3945-led.h
@@ -54,7 +54,7 @@ struct iwl3945_led {
 	int (*led_on) (struct iwl3945_priv *priv, int led_id);
 	int (*led_off) (struct iwl3945_priv *priv, int led_id);
 	int (*led_pattern) (struct iwl3945_priv *priv, int led_id,
-			    enum led_brightness brightness);
+			    unsigned int idx);
 
 	enum led_type type;
 	unsigned int registered;
diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.c b/drivers/net/wireless/iwlwifi/iwl-3945.c
index 94e177a9f51c..c2a76785b665 100644
--- a/drivers/net/wireless/iwlwifi/iwl-3945.c
+++ b/drivers/net/wireless/iwlwifi/iwl-3945.c
@@ -514,6 +514,23 @@ static inline void iwl3945_dbg_report_frame(struct iwl3945_priv *priv,
 }
 #endif
 
+/* This is necessary only for a number of statistics, see the caller. */
+static int iwl3945_is_network_packet(struct iwl3945_priv *priv,
+		struct ieee80211_hdr *header)
+{
+	/* Filter incoming packets to determine if they are targeted toward
+	 * this network, discarding packets coming from ourselves */
+	switch (priv->iw_mode) {
+	case IEEE80211_IF_TYPE_IBSS: /* Header: Dest. | Source    | BSSID */
+		/* packets to our IBSS update information */
+		return !compare_ether_addr(header->addr3, priv->bssid);
+	case IEEE80211_IF_TYPE_STA: /* Header: Dest. | AP{BSSID} | Source */
+		/* packets to our IBSS update information */
+		return !compare_ether_addr(header->addr2, priv->bssid);
+	default:
+		return 1;
+	}
+}
 
 static void iwl3945_add_radiotap(struct iwl3945_priv *priv,
 				 struct sk_buff *skb,
@@ -608,12 +625,12 @@ static void iwl3945_add_radiotap(struct iwl3945_priv *priv,
 	stats->flag |= RX_FLAG_RADIOTAP;
 }
 
-static void iwl3945_handle_data_packet(struct iwl3945_priv *priv, int is_data,
+static void iwl3945_pass_packet_to_mac80211(struct iwl3945_priv *priv,
 				   struct iwl3945_rx_mem_buffer *rxb,
 				   struct ieee80211_rx_status *stats)
 {
-	struct ieee80211_hdr *hdr;
 	struct iwl3945_rx_packet *pkt = (struct iwl3945_rx_packet *)rxb->skb->data;
+	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)IWL_RX_DATA(pkt);
 	struct iwl3945_rx_frame_hdr *rx_hdr = IWL_RX_HDR(pkt);
 	struct iwl3945_rx_frame_end *rx_end = IWL_RX_END(pkt);
 	short len = le16_to_cpu(rx_hdr->len);
@@ -635,8 +652,6 @@ static void iwl3945_handle_data_packet(struct iwl3945_priv *priv, int is_data,
 	/* Set the size of the skb to the size of the frame */
 	skb_put(rxb->skb, le16_to_cpu(rx_hdr->len));
 
-	hdr = (void *)rxb->skb->data;
-
 	if (iwl3945_param_hwcrypto)
 		iwl3945_set_decrypted_flag(priv, rxb->skb,
 				       le32_to_cpu(rx_end->status), stats);
@@ -645,7 +660,7 @@ static void iwl3945_handle_data_packet(struct iwl3945_priv *priv, int is_data,
 		iwl3945_add_radiotap(priv, rxb->skb, rx_hdr, stats);
 
 #ifdef CONFIG_IWL3945_LEDS
-	if (is_data)
+	if (ieee80211_is_data(hdr->frame_control))
 		priv->rxtxpackets += len;
 #endif
 	ieee80211_rx_irqsafe(priv->hw, rxb->skb, stats);
@@ -694,7 +709,7 @@ static void iwl3945_rx_reply_rx(struct iwl3945_priv *priv,
 	}
 
 	if (priv->iw_mode == IEEE80211_IF_TYPE_MNTR) {
-		iwl3945_handle_data_packet(priv, 1, rxb, &rx_status);
+		iwl3945_pass_packet_to_mac80211(priv, rxb, &rx_status);
 		return;
 	}
 
@@ -842,27 +857,12 @@ static void iwl3945_rx_reply_rx(struct iwl3945_priv *priv,
 			}
 		}
 
-		iwl3945_handle_data_packet(priv, 0, rxb, &rx_status);
-		break;
-
-	case IEEE80211_FTYPE_CTL:
-		break;
-
-	case IEEE80211_FTYPE_DATA: {
-		DECLARE_MAC_BUF(mac1);
-		DECLARE_MAC_BUF(mac2);
-		DECLARE_MAC_BUF(mac3);
-
-		if (unlikely(iwl3945_is_duplicate_packet(priv, header)))
-			IWL_DEBUG_DROP("Dropping (dup): %s, %s, %s\n",
-				       print_mac(mac1, header->addr1),
-				       print_mac(mac2, header->addr2),
-				       print_mac(mac3, header->addr3));
-		else
-			iwl3945_handle_data_packet(priv, 1, rxb, &rx_status);
+	case IEEE80211_FTYPE_DATA:
+		/* fall through */
+	default:
+		iwl3945_pass_packet_to_mac80211(priv, rxb, &rx_status);
 		break;
 	}
-	}
 }
 
 int iwl3945_hw_txq_attach_buf_to_tfd(struct iwl3945_priv *priv, void *ptr,
diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.h b/drivers/net/wireless/iwlwifi/iwl-3945.h
index 9c0a09eaca6f..fa81ba1af3d3 100644
--- a/drivers/net/wireless/iwlwifi/iwl-3945.h
+++ b/drivers/net/wireless/iwlwifi/iwl-3945.h
@@ -510,8 +510,6 @@ struct iwl3945_ucode {
 	u8 data[0];		/* data in same order as "size" elements */
 };
 
-#define IWL_IBSS_MAC_HASH_SIZE 32
-
 struct iwl3945_ibss_seq {
 	u8 mac[ETH_ALEN];
 	u16 seq_num;
@@ -569,17 +567,8 @@ extern int iwl3945_send_add_station(struct iwl3945_priv *priv,
 				struct iwl3945_addsta_cmd *sta, u8 flags);
 extern u8 iwl3945_add_station(struct iwl3945_priv *priv, const u8 *bssid,
 			  int is_ap, u8 flags);
-extern int iwl3945_is_network_packet(struct iwl3945_priv *priv,
-				 struct ieee80211_hdr *header);
 extern int iwl3945_power_init_handle(struct iwl3945_priv *priv);
 extern int iwl3945_eeprom_init(struct iwl3945_priv *priv);
-extern void iwl3945_handle_data_packet_monitor(struct iwl3945_priv *priv,
-					   struct iwl3945_rx_mem_buffer *rxb,
-					   void *data, short len,
-					   struct ieee80211_rx_status *stats,
-					   u16 phy_flags);
-extern int iwl3945_is_duplicate_packet(struct iwl3945_priv *priv,
-				       struct ieee80211_hdr *header);
 extern int iwl3945_rx_queue_alloc(struct iwl3945_priv *priv);
 extern void iwl3945_rx_queue_reset(struct iwl3945_priv *priv,
 			       struct iwl3945_rx_queue *rxq);
@@ -805,6 +794,7 @@ struct iwl3945_priv {
 	u8 last_blink_rate;
 	u8 allow_blinking;
 	unsigned int rxtxpackets;
+	u64 led_tpt;
 #endif
 
 
@@ -859,14 +849,6 @@ struct iwl3945_priv {
 	u32 last_beacon_time;
 	u64 last_tsf;
 
-	/* Duplicate packet detection */
-	u16 last_seq_num;
-	u16 last_frag_num;
-	unsigned long last_packet_time;
-
-	/* Hash table for finding stations in IBSS network */
-	struct list_head ibss_mac_hash[IWL_IBSS_MAC_HASH_SIZE];
-
 	/* eeprom */
 	struct iwl3945_eeprom eeprom;
 
diff --git a/drivers/net/wireless/iwlwifi/iwl-4965-hw.h b/drivers/net/wireless/iwlwifi/iwl-4965-hw.h
index 10f630e1afa6..fce950f4163c 100644
--- a/drivers/net/wireless/iwlwifi/iwl-4965-hw.h
+++ b/drivers/net/wireless/iwlwifi/iwl-4965-hw.h
@@ -819,6 +819,7 @@ enum {
 #define IWL49_NUM_FIFOS 	7
 #define IWL49_CMD_FIFO_NUM	4
 #define IWL49_NUM_QUEUES	16
+#define IWL49_NUM_AMPDU_QUEUES	8
 
 /**
  * struct iwl_tfd_frame_data
diff --git a/drivers/net/wireless/iwlwifi/iwl-4965-rs.c b/drivers/net/wireless/iwlwifi/iwl-4965-rs.c
index c7ebb3bf06f5..3ccb84aa5dbc 100644
--- a/drivers/net/wireless/iwlwifi/iwl-4965-rs.c
+++ b/drivers/net/wireless/iwlwifi/iwl-4965-rs.c
@@ -2265,9 +2265,7 @@ static void rs_rate_init(void *priv_rate, void *priv_sta,
 
 	/* as default allow aggregation for all tids */
 	lq_sta->tx_agg_tid_en = IWL_AGG_ALL_TID;
-#ifdef CONFIG_MAC80211_DEBUGFS
 	lq_sta->drv = priv;
-#endif
 
 	rs_initialize_lq(priv, conf, sta);
 }
diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c
index 04365b39279c..9afecb813716 100644
--- a/drivers/net/wireless/iwlwifi/iwl-4965.c
+++ b/drivers/net/wireless/iwlwifi/iwl-4965.c
@@ -49,9 +49,17 @@
 static int iwl4965_send_tx_power(struct iwl_priv *priv);
 static int iwl4965_hw_get_temperature(const struct iwl_priv *priv);
 
+/* Change firmware file name, using "-" and incrementing number,
+ *   *only* when uCode interface or architecture changes so that it
+ *   is not compatible with earlier drivers.
+ * This number will also appear in << 8 position of 1st dword of uCode file */
+#define IWL4965_UCODE_API "-2"
+
+
 /* module parameters */
 static struct iwl_mod_params iwl4965_mod_params = {
 	.num_of_queues = IWL49_NUM_QUEUES,
+	.num_of_ampdu_queues = IWL49_NUM_AMPDU_QUEUES,
 	.enable_qos = 1,
 	.amsdu_size_8K = 1,
 	.restart_fw = 1,
@@ -642,6 +650,18 @@ static void iwl4965_gain_computation(struct iwl_priv *priv,
 	data->beacon_count = 0;
 }
 
+static void iwl4965_rts_tx_cmd_flag(struct ieee80211_tx_info *info,
+			__le32 *tx_flags)
+{
+	if (info->flags & IEEE80211_TX_CTL_USE_RTS_CTS) {
+		*tx_flags |= TX_CMD_FLG_RTS_MSK;
+		*tx_flags &= ~TX_CMD_FLG_CTS_MSK;
+	} else if (info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT) {
+		*tx_flags &= ~TX_CMD_FLG_RTS_MSK;
+		*tx_flags |= TX_CMD_FLG_CTS_MSK;
+	}
+}
+
 static void iwl4965_bg_txpower_work(struct work_struct *work)
 {
 	struct iwl_priv *priv = container_of(work, struct iwl_priv,
@@ -1931,9 +1951,11 @@ static int iwl4965_txq_agg_disable(struct iwl_priv *priv, u16 txq_id,
 {
 	int ret = 0;
 
-	if (IWL49_FIRST_AMPDU_QUEUE > txq_id) {
-		IWL_WARNING("queue number too small: %d, must be > %d\n",
-				txq_id, IWL49_FIRST_AMPDU_QUEUE);
+	if ((IWL49_FIRST_AMPDU_QUEUE > txq_id) ||
+	    (IWL49_FIRST_AMPDU_QUEUE + IWL49_NUM_AMPDU_QUEUES <= txq_id)) {
+		IWL_WARNING("queue number out of range: %d, must be %d to %d\n",
+			txq_id, IWL49_FIRST_AMPDU_QUEUE,
+			IWL49_FIRST_AMPDU_QUEUE + IWL49_NUM_AMPDU_QUEUES - 1);
 		return -EINVAL;
 	}
 
@@ -2000,9 +2022,13 @@ static int iwl4965_txq_agg_enable(struct iwl_priv *priv, int txq_id,
 	int ret;
 	u16 ra_tid;
 
-	if (IWL49_FIRST_AMPDU_QUEUE > txq_id)
-		IWL_WARNING("queue number too small: %d, must be > %d\n",
-			txq_id, IWL49_FIRST_AMPDU_QUEUE);
+	if ((IWL49_FIRST_AMPDU_QUEUE > txq_id) ||
+	    (IWL49_FIRST_AMPDU_QUEUE + IWL49_NUM_AMPDU_QUEUES <= txq_id)) {
+		IWL_WARNING("queue number out of range: %d, must be %d to %d\n",
+			txq_id, IWL49_FIRST_AMPDU_QUEUE,
+			IWL49_FIRST_AMPDU_QUEUE + IWL49_NUM_AMPDU_QUEUES - 1);
+		return -EINVAL;
+	}
 
 	ra_tid = BUILD_RAxTID(sta_id, tid);
 
@@ -2372,6 +2398,7 @@ static struct iwl_hcmd_utils_ops iwl4965_hcmd_utils = {
 	.build_addsta_hcmd = iwl4965_build_addsta_hcmd,
 	.chain_noise_reset = iwl4965_chain_noise_reset,
 	.gain_computation = iwl4965_gain_computation,
+	.rts_tx_cmd_flag = iwl4965_rts_tx_cmd_flag,
 };
 
 static struct iwl_lib_ops iwl4965_lib = {
@@ -2434,6 +2461,9 @@ struct iwl_cfg iwl4965_agn_cfg = {
 	.mod_params = &iwl4965_mod_params,
 };
 
+/* Module firmware */
+MODULE_FIRMWARE("iwlwifi-4965" IWL4965_UCODE_API ".ucode");
+
 module_param_named(antenna, iwl4965_mod_params.antenna, int, 0444);
 MODULE_PARM_DESC(antenna, "select antenna (1=Main, 2=Aux, default 0 [both])");
 module_param_named(disable, iwl4965_mod_params.disable, int, 0444);
diff --git a/drivers/net/wireless/iwlwifi/iwl-5000-hw.h b/drivers/net/wireless/iwlwifi/iwl-5000-hw.h
index 4efe0c06b5b2..17d4f31c5934 100644
--- a/drivers/net/wireless/iwlwifi/iwl-5000-hw.h
+++ b/drivers/net/wireless/iwlwifi/iwl-5000-hw.h
@@ -81,6 +81,7 @@
 #define IWL50_QUEUE_SIZE                 256
 #define IWL50_CMD_FIFO_NUM                 7
 #define IWL50_NUM_QUEUES                  20
+#define IWL50_NUM_AMPDU_QUEUES		  10
 #define IWL50_FIRST_AMPDU_QUEUE		  10
 
 #define IWL_sta_id_POS 12
diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c
index 717db0d5ffb3..878d6193b232 100644
--- a/drivers/net/wireless/iwlwifi/iwl-5000.c
+++ b/drivers/net/wireless/iwlwifi/iwl-5000.c
@@ -370,6 +370,16 @@ static void iwl5000_chain_noise_reset(struct iwl_priv *priv)
 	}
 }
 
+static void iwl5000_rts_tx_cmd_flag(struct ieee80211_tx_info *info,
+			__le32 *tx_flags)
+{
+	if ((info->flags & IEEE80211_TX_CTL_USE_RTS_CTS) ||
+	    (info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT))
+		*tx_flags |= TX_CMD_FLG_RTS_CTS_MSK;
+	else
+		*tx_flags &= ~TX_CMD_FLG_RTS_CTS_MSK;
+}
+
 static struct iwl_sensitivity_ranges iwl5000_sensitivity = {
 	.min_nrg_cck = 95,
 	.max_nrg_cck = 0,
@@ -1006,9 +1016,13 @@ static int iwl5000_txq_agg_enable(struct iwl_priv *priv, int txq_id,
 	int ret;
 	u16 ra_tid;
 
-	if (IWL50_FIRST_AMPDU_QUEUE > txq_id)
-		IWL_WARNING("queue number too small: %d, must be > %d\n",
-			txq_id, IWL50_FIRST_AMPDU_QUEUE);
+	if ((IWL50_FIRST_AMPDU_QUEUE > txq_id) ||
+	    (IWL50_FIRST_AMPDU_QUEUE + IWL50_NUM_AMPDU_QUEUES <= txq_id)) {
+		IWL_WARNING("queue number out of range: %d, must be %d to %d\n",
+			txq_id, IWL50_FIRST_AMPDU_QUEUE,
+			IWL50_FIRST_AMPDU_QUEUE + IWL50_NUM_AMPDU_QUEUES - 1);
+		return -EINVAL;
+	}
 
 	ra_tid = BUILD_RAxTID(sta_id, tid);
 
@@ -1067,9 +1081,11 @@ static int iwl5000_txq_agg_disable(struct iwl_priv *priv, u16 txq_id,
 {
 	int ret;
 
-	if (IWL50_FIRST_AMPDU_QUEUE > txq_id) {
-		IWL_WARNING("queue number too small: %d, must be > %d\n",
-				txq_id, IWL50_FIRST_AMPDU_QUEUE);
+	if ((IWL50_FIRST_AMPDU_QUEUE > txq_id) ||
+	    (IWL50_FIRST_AMPDU_QUEUE + IWL50_NUM_AMPDU_QUEUES <= txq_id)) {
+		IWL_WARNING("queue number out of range: %d, must be %d to %d\n",
+			txq_id, IWL50_FIRST_AMPDU_QUEUE,
+			IWL50_FIRST_AMPDU_QUEUE + IWL50_NUM_AMPDU_QUEUES - 1);
 		return -EINVAL;
 	}
 
@@ -1437,6 +1453,7 @@ static struct iwl_hcmd_utils_ops iwl5000_hcmd_utils = {
 	.build_addsta_hcmd = iwl5000_build_addsta_hcmd,
 	.gain_computation = iwl5000_gain_computation,
 	.chain_noise_reset = iwl5000_chain_noise_reset,
+	.rts_tx_cmd_flag = iwl5000_rts_tx_cmd_flag,
 };
 
 static struct iwl_lib_ops iwl5000_lib = {
@@ -1490,6 +1507,7 @@ static struct iwl_ops iwl5000_ops = {
 
 static struct iwl_mod_params iwl50_mod_params = {
 	.num_of_queues = IWL50_NUM_QUEUES,
+	.num_of_ampdu_queues = IWL50_NUM_AMPDU_QUEUES,
 	.enable_qos = 1,
 	.amsdu_size_8K = 1,
 	.restart_fw = 1,
@@ -1506,6 +1524,24 @@ struct iwl_cfg iwl5300_agn_cfg = {
 	.mod_params = &iwl50_mod_params,
 };
 
+struct iwl_cfg iwl5100_bg_cfg = {
+	.name = "5100BG",
+	.fw_name = "iwlwifi-5000" IWL5000_UCODE_API ".ucode",
+	.sku = IWL_SKU_G,
+	.ops = &iwl5000_ops,
+	.eeprom_size = IWL_5000_EEPROM_IMG_SIZE,
+	.mod_params = &iwl50_mod_params,
+};
+
+struct iwl_cfg iwl5100_abg_cfg = {
+	.name = "5100ABG",
+	.fw_name = "iwlwifi-5000" IWL5000_UCODE_API ".ucode",
+	.sku = IWL_SKU_A|IWL_SKU_G,
+	.ops = &iwl5000_ops,
+	.eeprom_size = IWL_5000_EEPROM_IMG_SIZE,
+	.mod_params = &iwl50_mod_params,
+};
+
 struct iwl_cfg iwl5100_agn_cfg = {
 	.name = "5100AGN",
 	.fw_name = "iwlwifi-5000" IWL5000_UCODE_API ".ucode",
diff --git a/drivers/net/wireless/iwlwifi/iwl-commands.h b/drivers/net/wireless/iwlwifi/iwl-commands.h
index fe05d60ebe63..e9bb1de0ce3f 100644
--- a/drivers/net/wireless/iwlwifi/iwl-commands.h
+++ b/drivers/net/wireless/iwlwifi/iwl-commands.h
@@ -556,6 +556,8 @@ enum {
 #define RXON_FLG_CHANNEL_MODE_MSK		__constant_cpu_to_le32(0x3 << 25)
 #define RXON_FLG_CHANNEL_MODE_PURE_40_MSK	__constant_cpu_to_le32(0x1 << 25)
 #define RXON_FLG_CHANNEL_MODE_MIXED_MSK		__constant_cpu_to_le32(0x2 << 25)
+/* CTS to self (if spec allows) flag */
+#define RXON_FLG_SELF_CTS_EN			__constant_cpu_to_le32(0x1<<30)
 
 /* rx_config filter flags */
 /* accept all data frames */
@@ -723,7 +725,7 @@ struct iwl4965_csa_notification {
  * transmission retry.  Device uses cw_max as a bit mask, ANDed with new CW
  * value, to cap the CW value.
  */
-struct iwl4965_ac_qos {
+struct iwl_ac_qos {
 	__le16 cw_min;
 	__le16 cw_max;
 	u8 aifsn;
@@ -745,9 +747,9 @@ struct iwl4965_ac_qos {
  * This command sets up timings for each of the 4 prioritized EDCA Tx FIFOs
  * 0: Background, 1: Best Effort, 2: Video, 3: Voice.
  */
-struct iwl4965_qosparam_cmd {
+struct iwl_qosparam_cmd {
 	__le32 qos_flags;
-	struct iwl4965_ac_qos ac[AC_NUM];
+	struct iwl_ac_qos ac[AC_NUM];
 } __attribute__ ((packed));
 
 /******************************************************************************
@@ -1139,6 +1141,11 @@ struct iwl4965_rx_mpdu_res_start {
 
 /* REPLY_TX Tx flags field */
 
+/* 1: Use RTS/CTS protocol or CTS-to-self if spec alows it
+ * before this frame. if CTS-to-self required check
+ * RXON_FLG_SELF_CTS_EN status. */
+#define TX_CMD_FLG_RTS_CTS_MSK __constant_cpu_to_le32(1 << 0)
+
 /* 1: Use Request-To-Send protocol before this frame.
  * Mutually exclusive vs. TX_CMD_FLG_CTS_MSK. */
 #define TX_CMD_FLG_RTS_MSK __constant_cpu_to_le32(1 << 1)
@@ -2092,6 +2099,9 @@ struct iwl_ct_kill_config {
  *
  *****************************************************************************/
 
+#define SCAN_CHANNEL_TYPE_PASSIVE __constant_cpu_to_le32(0)
+#define SCAN_CHANNEL_TYPE_ACTIVE  __constant_cpu_to_le32(1)
+
 /**
  * struct iwl_scan_channel - entry in REPLY_SCAN_CMD channel table
  *
@@ -2115,12 +2125,12 @@ struct iwl_scan_channel {
 	/*
 	 * type is defined as:
 	 * 0:0 1 = active, 0 = passive
-	 * 1:4 SSID direct bit map; if a bit is set, then corresponding
+	 * 1:20 SSID direct bit map; if a bit is set, then corresponding
 	 *     SSID IE is transmitted in probe request.
-	 * 5:7 reserved
+	 * 21:31 reserved
 	 */
-	u8 type;
-	u8 channel;	/* band is selected by iwl4965_scan_cmd "flags" field */
+	__le32 type;
+	__le16 channel;	/* band is selected by iwl_scan_cmd "flags" field */
 	u8 tx_gain;		/* gain for analog radio */
 	u8 dsp_atten;		/* gain for DSP */
 	__le16 active_dwell;	/* in 1024-uSec TU (time units), typ 5-50 */
@@ -2140,9 +2150,9 @@ struct iwl_ssid_ie {
 	u8 ssid[32];
 } __attribute__ ((packed));
 
-#define PROBE_OPTION_MAX        0x4
+#define PROBE_OPTION_MAX        	0x14
 #define TX_CMD_LIFE_TIME_INFINITE	__constant_cpu_to_le32(0xFFFFFFFF)
-#define IWL_GOOD_CRC_TH		__constant_cpu_to_le16(1)
+#define IWL_GOOD_CRC_TH			__constant_cpu_to_le16(1)
 #define IWL_MAX_SCAN_SIZE 1024
 
 /*
@@ -2919,7 +2929,7 @@ struct iwl5000_calibration_chain_noise_gain_cmd {
  * For each of 3 possible LEDs (Activity/Link/Tech, selected by "id" field),
  * this command turns it on or off, or sets up a periodic blinking cycle.
  */
-struct iwl4965_led_cmd {
+struct iwl_led_cmd {
 	__le32 interval;	/* "interval" in uSec */
 	u8 id;			/* 1: Activity, 2: Link, 3: Tech */
 	u8 off;			/* # intervals off while blinking;
diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c
index eee220cf52a2..a44188bf4459 100644
--- a/drivers/net/wireless/iwlwifi/iwl-core.c
+++ b/drivers/net/wireless/iwlwifi/iwl-core.c
@@ -825,7 +825,7 @@ int iwl_setup_mac(struct iwl_priv *priv)
 	hw->queues = 4;
 	/* queues to support 11n aggregation */
 	if (priv->cfg->sku & IWL_SKU_N)
-		hw->ampdu_queues = 12;
+		hw->ampdu_queues = priv->cfg->mod_params->num_of_ampdu_queues;
 
 	hw->conf.beacon_int = 100;
 
diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h
index dafd62c7dfd6..db66114f1e56 100644
--- a/drivers/net/wireless/iwlwifi/iwl-core.h
+++ b/drivers/net/wireless/iwlwifi/iwl-core.h
@@ -70,7 +70,7 @@ struct iwl_host_cmd;
 struct iwl_cmd;
 
 
-#define IWLWIFI_VERSION "1.2.26k"
+#define IWLWIFI_VERSION "1.3.27k"
 #define DRV_COPYRIGHT	"Copyright(c) 2003-2008 Intel Corporation"
 
 #define IWL_PCI_DEVICE(dev, subdev, cfg) \
@@ -93,6 +93,8 @@ struct iwl_hcmd_utils_ops {
 			u16 min_average_noise_antennat_i,
 			u32 min_average_noise);
 	void (*chain_noise_reset)(struct iwl_priv *priv);
+	void (*rts_tx_cmd_flag)(struct ieee80211_tx_info *info,
+			__le32 *tx_flags);
 };
 
 struct iwl_lib_ops {
@@ -157,6 +159,7 @@ struct iwl_mod_params {
 	int debug;		/* def: 0 = minimal debug log messages */
 	int disable_hw_scan;	/* def: 0 = use h/w scan */
 	int num_of_queues;	/* def: HW dependent */
+	int num_of_ampdu_queues;/* def: HW dependent */
 	int enable_qos;		/* def: 1 = use quality of service */
 	int disable_11n;	/* def: 0 = disable 11n capabilities */
 	int amsdu_size_8K;	/* def: 1 = enable 8K amsdu size */
diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h
index c8d3d97cf48d..4d789e353e3a 100644
--- a/drivers/net/wireless/iwlwifi/iwl-dev.h
+++ b/drivers/net/wireless/iwlwifi/iwl-dev.h
@@ -51,12 +51,8 @@ extern struct iwl_cfg iwl4965_agn_cfg;
 extern struct iwl_cfg iwl5300_agn_cfg;
 extern struct iwl_cfg iwl5100_agn_cfg;
 extern struct iwl_cfg iwl5350_agn_cfg;
-
-/* Change firmware file name, using "-" and incrementing number,
- *   *only* when uCode interface or architecture changes so that it
- *   is not compatible with earlier drivers.
- * This number will also appear in << 8 position of 1st dword of uCode file */
-#define IWL4965_UCODE_API "-1"
+extern struct iwl_cfg iwl5100_bg_cfg;
+extern struct iwl_cfg iwl5100_abg_cfg;
 
 /* CT-KILL constants */
 #define CT_KILL_THRESHOLD	110 /* in Celsius */
@@ -280,7 +276,7 @@ struct iwl_cmd {
 	struct iwl_cmd_header hdr;	/* uCode API */
 	union {
 		struct iwl_addsta_cmd addsta;
-		struct iwl4965_led_cmd led;
+		struct iwl_led_cmd led;
 		u32 flags;
 		u8 val8;
 		u16 val16;
@@ -288,7 +284,7 @@ struct iwl_cmd {
 		struct iwl4965_bt_cmd bt;
 		struct iwl4965_rxon_time_cmd rxon_time;
 		struct iwl4965_powertable_cmd powertable;
-		struct iwl4965_qosparam_cmd qosparam;
+		struct iwl_qosparam_cmd qosparam;
 		struct iwl_tx_cmd tx;
 		struct iwl4965_tx_beacon_cmd tx_beacon;
 		struct iwl4965_rxon_assoc_cmd rxon_assoc;
@@ -433,7 +429,7 @@ struct iwl_ht_info {
 	u8 non_GF_STA_present;
 };
 
-union iwl4965_qos_capabity {
+union iwl_qos_capabity {
 	struct {
 		u8 edca_count:4;	/* bit 0-3 */
 		u8 q_ack:1;		/* bit 4 */
@@ -454,11 +450,11 @@ union iwl4965_qos_capabity {
 };
 
 /* QoS structures */
-struct iwl4965_qos_info {
+struct iwl_qos_info {
 	int qos_enable;
 	int qos_active;
-	union iwl4965_qos_capabity qos_cap;
-	struct iwl4965_qosparam_cmd def_qos_parm;
+	union iwl_qos_capabity qos_cap;
+	struct iwl_qosparam_cmd def_qos_parm;
 };
 
 #define STA_PS_STATUS_WAKE             0
@@ -490,8 +486,6 @@ struct iwl_ucode {
 	u8 data[0];		/* data in same order as "size" elements */
 };
 
-#define IWL_IBSS_MAC_HASH_SIZE 32
-
 struct iwl4965_ibss_seq {
 	u8 mac[ETH_ALEN];
 	u16 seq_num;
@@ -933,7 +927,7 @@ struct iwl_priv {
 #endif
 
 #ifdef CONFIG_IWLWIFI_LEDS
-	struct iwl4965_led led[IWL_LED_TRG_MAX];
+	struct iwl_led led[IWL_LED_TRG_MAX];
 	unsigned long last_blink_time;
 	u8 last_blink_rate;
 	u8 allow_blinking;
@@ -1042,7 +1036,7 @@ struct iwl_priv {
 	u16 assoc_capability;
 	u8 ps_mode;
 
-	struct iwl4965_qos_info qos_data;
+	struct iwl_qos_info qos_data;
 
 	struct workqueue_struct *workqueue;
 
@@ -1065,7 +1059,6 @@ struct iwl_priv {
 	struct delayed_work init_alive_start;
 	struct delayed_work alive_start;
 	struct delayed_work scan_check;
-	struct delayed_work post_associate;
 	/* TX Power */
 	s8 tx_power_user_lmt;
 	s8 tx_power_channel_lmt;
diff --git a/drivers/net/wireless/iwlwifi/iwl-led.c b/drivers/net/wireless/iwlwifi/iwl-led.c
index aa6ad18494ce..899d7a2567a8 100644
--- a/drivers/net/wireless/iwlwifi/iwl-led.c
+++ b/drivers/net/wireless/iwlwifi/iwl-led.c
@@ -44,14 +44,21 @@
 #include "iwl-io.h"
 #include "iwl-helpers.h"
 
-#define IWL_1MB_RATE (128 * 1024)
-#define IWL_LED_THRESHOLD (16)
-#define IWL_MAX_BLINK_TBL (10)
+#ifdef CONFIG_IWLWIFI_DEBUG
+static const char *led_type_str[] = {
+	__stringify(IWL_LED_TRG_TX),
+	__stringify(IWL_LED_TRG_RX),
+	__stringify(IWL_LED_TRG_ASSOC),
+	__stringify(IWL_LED_TRG_RADIO),
+	NULL
+};
+#endif /* CONFIG_IWLWIFI_DEBUG */
+
 
 static const struct {
 	u16 tpt;
 	u8 on_time;
-	u8 of_time;
+	u8 off_time;
 } blink_tbl[] =
 {
 	{300, 25, 25},
@@ -63,26 +70,31 @@ static const struct {
 	{15, 95, 95 },
 	{10, 110, 110},
 	{5, 130, 130},
-	{0, 167, 167}
+	{0, 167, 167},
+/* SOLID_ON */
+	{-1, IWL_LED_SOLID, 0}
 };
 
-static int iwl_led_cmd_callback(struct iwl_priv *priv,
-				struct iwl_cmd *cmd, struct sk_buff *skb)
+#define IWL_1MB_RATE (128 * 1024)
+#define IWL_LED_THRESHOLD (16)
+#define IWL_MAX_BLINK_TBL (ARRAY_SIZE(blink_tbl) - 1) /* exclude SOLID_ON */
+#define IWL_SOLID_BLINK_IDX (ARRAY_SIZE(blink_tbl) - 1)
+
+/*  [0-256] -> [0..8] FIXME: we need [0..10] */
+static inline int iwl_brightness_to_idx(enum led_brightness brightness)
 {
-	return 1;
+	return fls(0x000000FF & (u32)brightness);
 }
 
-
 /* Send led command */
-static int iwl_send_led_cmd(struct iwl_priv *priv,
-			    struct iwl4965_led_cmd *led_cmd)
+static int iwl_send_led_cmd(struct iwl_priv *priv, struct iwl_led_cmd *led_cmd)
 {
 	struct iwl_host_cmd cmd = {
 		.id = REPLY_LEDS_CMD,
-		.len = sizeof(struct iwl4965_led_cmd),
+		.len = sizeof(struct iwl_led_cmd),
 		.data = led_cmd,
 		.meta.flags = CMD_ASYNC,
-		.meta.u.callback = iwl_led_cmd_callback
+		.meta.u.callback = NULL,
 	};
 	u32 reg;
 
@@ -93,33 +105,20 @@ static int iwl_send_led_cmd(struct iwl_priv *priv,
 	return iwl_send_cmd(priv, &cmd);
 }
 
-
-/* Set led on command */
-static int iwl4965_led_on(struct iwl_priv *priv, int led_id)
-{
-	struct iwl4965_led_cmd led_cmd = {
-		.id = led_id,
-		.on = IWL_LED_SOLID,
-		.off = 0,
-		.interval = IWL_DEF_LED_INTRVL
-	};
-	return iwl_send_led_cmd(priv, &led_cmd);
-}
-
-/* Set led on command */
+/* Set led pattern command */
 static int iwl4965_led_pattern(struct iwl_priv *priv, int led_id,
-			       enum led_brightness brightness)
+			       unsigned int idx)
 {
-	struct iwl4965_led_cmd led_cmd = {
+	struct iwl_led_cmd led_cmd = {
 		.id = led_id,
-		.on = brightness,
-		.off = brightness,
 		.interval = IWL_DEF_LED_INTRVL
 	};
-	if (brightness == LED_FULL) {
-		led_cmd.on = IWL_LED_SOLID;
-		led_cmd.off = 0;
-	}
+
+	BUG_ON(idx > IWL_MAX_BLINK_TBL);
+
+	led_cmd.on = blink_tbl[idx].on_time;
+	led_cmd.off = blink_tbl[idx].off_time;
+
 	return iwl_send_led_cmd(priv, &led_cmd);
 }
 
@@ -132,10 +131,22 @@ static int iwl4965_led_on_reg(struct iwl_priv *priv, int led_id)
 }
 
 #if 0
+/* Set led on command */
+static int iwl4965_led_on(struct iwl_priv *priv, int led_id)
+{
+	struct iwl_led_cmd led_cmd = {
+		.id = led_id,
+		.on = IWL_LED_SOLID,
+		.off = 0,
+		.interval = IWL_DEF_LED_INTRVL
+	};
+	return iwl_send_led_cmd(priv, &led_cmd);
+}
+
 /* Set led off command */
 int iwl4965_led_off(struct iwl_priv *priv, int led_id)
 {
-	struct iwl4965_led_cmd led_cmd = {
+	struct iwl_led_cmd led_cmd = {
 		.id = led_id,
 		.on = 0,
 		.off = 0,
@@ -155,25 +166,10 @@ static int iwl4965_led_off_reg(struct iwl_priv *priv, int led_id)
 	return 0;
 }
 
-/* Set led blink command */
-static int iwl4965_led_not_solid(struct iwl_priv *priv, int led_id,
-			       u8 brightness)
-{
-	struct iwl4965_led_cmd led_cmd = {
-		.id = led_id,
-		.on = brightness,
-		.off = brightness,
-		.interval = IWL_DEF_LED_INTRVL
-	};
-
-	return iwl_send_led_cmd(priv, &led_cmd);
-}
-
-
 /*
  * brightness call back function for Tx/Rx LED
  */
-static int iwl4965_led_associated(struct iwl_priv *priv, int led_id)
+static int iwl_led_associated(struct iwl_priv *priv, int led_id)
 {
 	if (test_bit(STATUS_EXIT_PENDING, &priv->status) ||
 	    !test_bit(STATUS_READY, &priv->status))
@@ -189,16 +185,18 @@ static int iwl4965_led_associated(struct iwl_priv *priv, int led_id)
 /*
  * brightness call back for association and radio
  */
-static void iwl4965_led_brightness_set(struct led_classdev *led_cdev,
+static void iwl_led_brightness_set(struct led_classdev *led_cdev,
 				       enum led_brightness brightness)
 {
-	struct iwl4965_led *led = container_of(led_cdev,
-					       struct iwl4965_led, led_dev);
+	struct iwl_led *led = container_of(led_cdev, struct iwl_led, led_dev);
 	struct iwl_priv *priv = led->priv;
 
 	if (test_bit(STATUS_EXIT_PENDING, &priv->status))
 		return;
 
+
+	IWL_DEBUG_LED("Led type = %s brightness = %d\n",
+			led_type_str[led->type], brightness);
 	switch (brightness) {
 	case LED_FULL:
 		if (led->type == IWL_LED_TRG_ASSOC)
@@ -215,8 +213,10 @@ static void iwl4965_led_brightness_set(struct led_classdev *led_cdev,
 			led->led_off(priv, IWL_LED_LINK);
 		break;
 	default:
-		if (led->led_pattern)
-			led->led_pattern(priv, IWL_LED_LINK, brightness);
+		if (led->led_pattern) {
+			int idx = iwl_brightness_to_idx(brightness);
+			led->led_pattern(priv, IWL_LED_LINK, idx);
+		}
 		break;
 	}
 }
@@ -226,8 +226,7 @@ static void iwl4965_led_brightness_set(struct led_classdev *led_cdev,
 /*
  * Register led class with the system
  */
-static int iwl_leds_register_led(struct iwl_priv *priv,
-				   struct iwl4965_led *led,
+static int iwl_leds_register_led(struct iwl_priv *priv, struct iwl_led *led,
 				   enum led_type type, u8 set_led,
 				   const char *name, char *trigger)
 {
@@ -235,7 +234,7 @@ static int iwl_leds_register_led(struct iwl_priv *priv,
 	int ret;
 
 	led->led_dev.name = name;
-	led->led_dev.brightness_set = iwl4965_led_brightness_set;
+	led->led_dev.brightness_set = iwl_led_brightness_set;
 	led->led_dev.default_trigger = trigger;
 
 	led->priv = priv;
@@ -259,32 +258,28 @@ static int iwl_leds_register_led(struct iwl_priv *priv,
 /*
  * calculate blink rate according to last 2 sec Tx/Rx activities
  */
-static inline u8 get_blink_rate(struct iwl_priv *priv)
+static int iwl_get_blink_rate(struct iwl_priv *priv)
 {
 	int i;
-	u8 blink_rate;
-	u64 current_tpt = priv->tx_stats[2].bytes + priv->rx_stats[2].bytes;
+	u64 current_tpt = priv->tx_stats[2].bytes;
+	/* FIXME: + priv->rx_stats[2].bytes; */
 	s64 tpt = current_tpt - priv->led_tpt;
 
 	if (tpt < 0) /* wrapparound */
 		tpt = -tpt;
 
+	IWL_DEBUG_LED("tpt %lld current_tpt %lld\n", tpt, current_tpt);
 	priv->led_tpt = current_tpt;
 
-	if (tpt < IWL_LED_THRESHOLD) {
+	if (!priv->allow_blinking)
 		i = IWL_MAX_BLINK_TBL;
-	} else {
+	else
 		for (i = 0; i < IWL_MAX_BLINK_TBL; i++)
 			if (tpt  > (blink_tbl[i].tpt * IWL_1MB_RATE))
 				break;
-	}
-	/* if 0 frame is transfered */
-	if ((i == IWL_MAX_BLINK_TBL) || !priv->allow_blinking)
-		blink_rate = IWL_LED_SOLID;
-	else
-		blink_rate = blink_tbl[i].on_time;
 
-	return blink_rate;
+	IWL_DEBUG_LED("LED BLINK IDX=%d", i);
+	return i;
 }
 
 static inline int is_rf_kill(struct iwl_priv *priv)
@@ -300,7 +295,7 @@ static inline int is_rf_kill(struct iwl_priv *priv)
  */
 void iwl_leds_background(struct iwl_priv *priv)
 {
-	u8 blink_rate;
+	u8 blink_idx;
 
 	if (test_bit(STATUS_EXIT_PENDING, &priv->status)) {
 		priv->last_blink_time = 0;
@@ -313,9 +308,10 @@ void iwl_leds_background(struct iwl_priv *priv)
 
 	if (!priv->allow_blinking) {
 		priv->last_blink_time = 0;
-		if (priv->last_blink_rate != IWL_LED_SOLID) {
-			priv->last_blink_rate = IWL_LED_SOLID;
-			iwl4965_led_on(priv, IWL_LED_LINK);
+		if (priv->last_blink_rate != IWL_SOLID_BLINK_IDX) {
+			priv->last_blink_rate = IWL_SOLID_BLINK_IDX;
+			iwl4965_led_pattern(priv, IWL_LED_LINK,
+					    IWL_SOLID_BLINK_IDX);
 		}
 		return;
 	}
@@ -324,21 +320,14 @@ void iwl_leds_background(struct iwl_priv *priv)
 			msecs_to_jiffies(1000)))
 		return;
 
-	blink_rate = get_blink_rate(priv);
+	blink_idx = iwl_get_blink_rate(priv);
 
 	/* call only if blink rate change */
-	if (blink_rate != priv->last_blink_rate) {
-		if (blink_rate != IWL_LED_SOLID) {
-			priv->last_blink_time = jiffies +
-						msecs_to_jiffies(1000);
-			iwl4965_led_not_solid(priv, IWL_LED_LINK, blink_rate);
-		} else {
-			priv->last_blink_time = 0;
-			iwl4965_led_on(priv, IWL_LED_LINK);
-		}
-	}
+	if (blink_idx != priv->last_blink_rate)
+		iwl4965_led_pattern(priv, IWL_LED_LINK, blink_idx);
 
-	priv->last_blink_rate = blink_rate;
+	priv->last_blink_time = jiffies;
+	priv->last_blink_rate = blink_idx;
 }
 EXPORT_SYMBOL(iwl_leds_background);
 
@@ -362,10 +351,8 @@ int iwl_leds_register(struct iwl_priv *priv)
 	priv->led[IWL_LED_TRG_RADIO].led_off = iwl4965_led_off_reg;
 	priv->led[IWL_LED_TRG_RADIO].led_pattern = NULL;
 
-	ret = iwl_leds_register_led(priv,
-				   &priv->led[IWL_LED_TRG_RADIO],
-				   IWL_LED_TRG_RADIO, 1,
-				   name, trigger);
+	ret = iwl_leds_register_led(priv, &priv->led[IWL_LED_TRG_RADIO],
+				   IWL_LED_TRG_RADIO, 1, name, trigger);
 	if (ret)
 		goto exit_fail;
 
@@ -373,10 +360,9 @@ int iwl_leds_register(struct iwl_priv *priv)
 	snprintf(name, sizeof(name), "iwl-%s:assoc",
 		 wiphy_name(priv->hw->wiphy));
 
-	ret = iwl_leds_register_led(priv,
-				   &priv->led[IWL_LED_TRG_ASSOC],
-				   IWL_LED_TRG_ASSOC, 0,
-				   name, trigger);
+	ret = iwl_leds_register_led(priv, &priv->led[IWL_LED_TRG_ASSOC],
+				   IWL_LED_TRG_ASSOC, 0, name, trigger);
+
 	/* for assoc always turn led on */
 	priv->led[IWL_LED_TRG_ASSOC].led_on = iwl4965_led_on_reg;
 	priv->led[IWL_LED_TRG_ASSOC].led_off = iwl4965_led_on_reg;
@@ -386,31 +372,26 @@ int iwl_leds_register(struct iwl_priv *priv)
 		goto exit_fail;
 
 	trigger = ieee80211_get_rx_led_name(priv->hw);
-	snprintf(name, sizeof(name), "iwl-%s:RX",
-		 wiphy_name(priv->hw->wiphy));
+	snprintf(name, sizeof(name), "iwl-%s:RX", wiphy_name(priv->hw->wiphy));
 
 
-	ret = iwl_leds_register_led(priv,
-				   &priv->led[IWL_LED_TRG_RX],
-				   IWL_LED_TRG_RX, 0,
-				   name, trigger);
+	ret = iwl_leds_register_led(priv, &priv->led[IWL_LED_TRG_RX],
+				   IWL_LED_TRG_RX, 0, name, trigger);
 
-	priv->led[IWL_LED_TRG_RX].led_on = iwl4965_led_associated;
-	priv->led[IWL_LED_TRG_RX].led_off = iwl4965_led_associated;
+	priv->led[IWL_LED_TRG_RX].led_on = iwl_led_associated;
+	priv->led[IWL_LED_TRG_RX].led_off = iwl_led_associated;
 	priv->led[IWL_LED_TRG_RX].led_pattern = iwl4965_led_pattern;
 
 	if (ret)
 		goto exit_fail;
 
 	trigger = ieee80211_get_tx_led_name(priv->hw);
-	snprintf(name, sizeof(name), "iwl-%s:TX",
-		 wiphy_name(priv->hw->wiphy));
-	ret = iwl_leds_register_led(priv,
-				   &priv->led[IWL_LED_TRG_TX],
-				   IWL_LED_TRG_TX, 0,
-				   name, trigger);
-	priv->led[IWL_LED_TRG_TX].led_on = iwl4965_led_associated;
-	priv->led[IWL_LED_TRG_TX].led_off = iwl4965_led_associated;
+	snprintf(name, sizeof(name), "iwl-%s:TX", wiphy_name(priv->hw->wiphy));
+	ret = iwl_leds_register_led(priv, &priv->led[IWL_LED_TRG_TX],
+				   IWL_LED_TRG_TX, 0, name, trigger);
+
+	priv->led[IWL_LED_TRG_TX].led_on = iwl_led_associated;
+	priv->led[IWL_LED_TRG_TX].led_off = iwl_led_associated;
 	priv->led[IWL_LED_TRG_TX].led_pattern = iwl4965_led_pattern;
 
 	if (ret)
@@ -425,7 +406,7 @@ exit_fail:
 EXPORT_SYMBOL(iwl_leds_register);
 
 /* unregister led class */
-static void iwl_leds_unregister_led(struct iwl4965_led *led, u8 set_led)
+static void iwl_leds_unregister_led(struct iwl_led *led, u8 set_led)
 {
 	if (!led->registered)
 		return;
diff --git a/drivers/net/wireless/iwlwifi/iwl-led.h b/drivers/net/wireless/iwlwifi/iwl-led.h
index 5bb04128cd65..1980ae5a7e82 100644
--- a/drivers/net/wireless/iwlwifi/iwl-led.h
+++ b/drivers/net/wireless/iwlwifi/iwl-led.h
@@ -49,14 +49,13 @@ enum led_type {
 };
 
 
-struct iwl4965_led {
+struct iwl_led {
 	struct iwl_priv *priv;
 	struct led_classdev led_dev;
 
 	int (*led_on) (struct iwl_priv *priv, int led_id);
 	int (*led_off) (struct iwl_priv *priv, int led_id);
-	int (*led_pattern) (struct iwl_priv *priv, int led_id,
-			    enum led_brightness brightness);
+	int (*led_pattern) (struct iwl_priv *priv, int led_id, unsigned int idx);
 
 	enum led_type type;
 	unsigned int registered;
diff --git a/drivers/net/wireless/iwlwifi/iwl-rx.c b/drivers/net/wireless/iwlwifi/iwl-rx.c
index 3e8500ecf598..e2d9afba38a5 100644
--- a/drivers/net/wireless/iwlwifi/iwl-rx.c
+++ b/drivers/net/wireless/iwlwifi/iwl-rx.c
@@ -29,6 +29,7 @@
 
 #include <linux/etherdevice.h>
 #include <net/mac80211.h>
+#include <asm/unaligned.h>
 #include "iwl-eeprom.h"
 #include "iwl-dev.h"
 #include "iwl-core.h"
@@ -829,23 +830,22 @@ static void iwl_add_radiotap(struct iwl_priv *priv,
 	iwl4965_rt->rt_hdr.it_pad = 0;
 
 	/* total header + data */
-	put_unaligned(cpu_to_le16(sizeof(*iwl4965_rt)),
-		      &iwl4965_rt->rt_hdr.it_len);
+	put_unaligned_le16(sizeof(*iwl4965_rt), &iwl4965_rt->rt_hdr.it_len);
 
 	/* Indicate all the fields we add to the radiotap header */
-	put_unaligned(cpu_to_le32((1 << IEEE80211_RADIOTAP_TSFT) |
-				  (1 << IEEE80211_RADIOTAP_FLAGS) |
-				  (1 << IEEE80211_RADIOTAP_RATE) |
-				  (1 << IEEE80211_RADIOTAP_CHANNEL) |
-				  (1 << IEEE80211_RADIOTAP_DBM_ANTSIGNAL) |
-				  (1 << IEEE80211_RADIOTAP_DBM_ANTNOISE) |
-				  (1 << IEEE80211_RADIOTAP_ANTENNA)),
-		      &iwl4965_rt->rt_hdr.it_present);
+	put_unaligned_le32((1 << IEEE80211_RADIOTAP_TSFT) |
+			   (1 << IEEE80211_RADIOTAP_FLAGS) |
+			   (1 << IEEE80211_RADIOTAP_RATE) |
+			   (1 << IEEE80211_RADIOTAP_CHANNEL) |
+			   (1 << IEEE80211_RADIOTAP_DBM_ANTSIGNAL) |
+			   (1 << IEEE80211_RADIOTAP_DBM_ANTNOISE) |
+			   (1 << IEEE80211_RADIOTAP_ANTENNA),
+			   &(iwl4965_rt->rt_hdr.it_present));
 
 	/* Zero the flags, we'll add to them as we go */
 	iwl4965_rt->rt_flags = 0;
 
-	put_unaligned(cpu_to_le64(tsf), &iwl4965_rt->rt_tsf);
+	put_unaligned_le64(tsf, &iwl4965_rt->rt_tsf);
 
 	iwl4965_rt->rt_dbmsignal = signal;
 	iwl4965_rt->rt_dbmnoise = noise;
@@ -853,17 +853,14 @@ static void iwl_add_radiotap(struct iwl_priv *priv,
 	/* Convert the channel frequency and set the flags */
 	put_unaligned(cpu_to_le16(stats->freq), &iwl4965_rt->rt_channelMHz);
 	if (!(phy_flags_hw & RX_RES_PHY_FLAGS_BAND_24_MSK))
-		put_unaligned(cpu_to_le16(IEEE80211_CHAN_OFDM |
-					  IEEE80211_CHAN_5GHZ),
-			      &iwl4965_rt->rt_chbitmask);
+		put_unaligned_le16(IEEE80211_CHAN_OFDM | IEEE80211_CHAN_5GHZ,
+				   &iwl4965_rt->rt_chbitmask);
 	else if (phy_flags_hw & RX_RES_PHY_FLAGS_MOD_CCK_MSK)
-		put_unaligned(cpu_to_le16(IEEE80211_CHAN_CCK |
-					  IEEE80211_CHAN_2GHZ),
-			      &iwl4965_rt->rt_chbitmask);
+		put_unaligned_le16(IEEE80211_CHAN_CCK | IEEE80211_CHAN_2GHZ,
+				   &iwl4965_rt->rt_chbitmask);
 	else	/* 802.11g */
-		put_unaligned(cpu_to_le16(IEEE80211_CHAN_OFDM |
-					  IEEE80211_CHAN_2GHZ),
-			      &iwl4965_rt->rt_chbitmask);
+		put_unaligned_le16(IEEE80211_CHAN_OFDM | IEEE80211_CHAN_2GHZ,
+				   &iwl4965_rt->rt_chbitmask);
 
 	if (rate == -1)
 		iwl4965_rt->rt_rate = 0;
diff --git a/drivers/net/wireless/iwlwifi/iwl-scan.c b/drivers/net/wireless/iwlwifi/iwl-scan.c
index 5b420b43af5c..efc750d2fc5c 100644
--- a/drivers/net/wireless/iwlwifi/iwl-scan.c
+++ b/drivers/net/wireless/iwlwifi/iwl-scan.c
@@ -38,8 +38,11 @@
 /* For active scan, listen ACTIVE_DWELL_TIME (msec) on each channel after
  * sending probe req.  This should be set long enough to hear probe responses
  * from more than one AP.  */
-#define IWL_ACTIVE_DWELL_TIME_24    (20)       /* all times in msec */
-#define IWL_ACTIVE_DWELL_TIME_52    (10)
+#define IWL_ACTIVE_DWELL_TIME_24    (30)       /* all times in msec */
+#define IWL_ACTIVE_DWELL_TIME_52    (20)
+
+#define IWL_ACTIVE_DWELL_FACTOR_24GHZ (3)
+#define IWL_ACTIVE_DWELL_FACTOR_52GHZ (2)
 
 /* For faster active scanning, scan will move to the next channel if fewer than
  * PLCP_QUIET_THRESH packets are heard on this channel within
@@ -48,7 +51,7 @@
  * no other traffic).
  * Disable "quiet" feature by setting PLCP_QUIET_THRESH to 0. */
 #define IWL_PLCP_QUIET_THRESH       __constant_cpu_to_le16(1)  /* packets */
-#define IWL_ACTIVE_QUIET_TIME       __constant_cpu_to_le16(5)  /* msec */
+#define IWL_ACTIVE_QUIET_TIME       __constant_cpu_to_le16(10)  /* msec */
 
 /* For passive scan, listen PASSIVE_DWELL_TIME (msec) on each channel.
  * Must be set longer than active dwell time.
@@ -58,10 +61,15 @@
 #define IWL_PASSIVE_DWELL_BASE      (100)
 #define IWL_CHANNEL_TUNE_TIME       5
 
+#define IWL_SCAN_PROBE_MASK(n) 	cpu_to_le32((BIT(n) | (BIT(n) - BIT(1))))
+
+
 static int scan_tx_ant[3] = {
 	RATE_MCS_ANT_A_MSK, RATE_MCS_ANT_B_MSK, RATE_MCS_ANT_C_MSK
 };
 
+
+
 static int iwl_is_empty_essid(const char *essid, int essid_len)
 {
 	/* Single white space is for Linksys APs */
@@ -226,8 +234,9 @@ static void iwl_rx_scan_start_notif(struct iwl_priv *priv,
 		       "(TSF: 0x%08X:%08X) - %d (beacon timer %u)\n",
 		       notif->channel,
 		       notif->band ? "bg" : "a",
-		       notif->tsf_high,
-		       notif->tsf_low, notif->status, notif->beacon_timer);
+		       le32_to_cpu(notif->tsf_high),
+		       le32_to_cpu(notif->tsf_low),
+		       notif->status, notif->beacon_timer);
 }
 
 /* Service SCAN_RESULTS_NOTIFICATION (0x83) */
@@ -332,19 +341,21 @@ void iwl_setup_rx_scan_handlers(struct iwl_priv *priv)
 EXPORT_SYMBOL(iwl_setup_rx_scan_handlers);
 
 static inline u16 iwl_get_active_dwell_time(struct iwl_priv *priv,
-						enum ieee80211_band band)
+					    enum ieee80211_band band,
+					    u8 n_probes)
 {
 	if (band == IEEE80211_BAND_5GHZ)
-		return IWL_ACTIVE_DWELL_TIME_52;
+		return IWL_ACTIVE_DWELL_TIME_52 +
+			IWL_ACTIVE_DWELL_FACTOR_52GHZ * (n_probes + 1);
 	else
-		return IWL_ACTIVE_DWELL_TIME_24;
+		return IWL_ACTIVE_DWELL_TIME_24 +
+			IWL_ACTIVE_DWELL_FACTOR_24GHZ * (n_probes + 1);
 }
 
 static u16 iwl_get_passive_dwell_time(struct iwl_priv *priv,
-					  enum ieee80211_band band)
+				      enum ieee80211_band band)
 {
-	u16 active = iwl_get_active_dwell_time(priv, band);
-	u16 passive = (band != IEEE80211_BAND_5GHZ) ?
+	u16 passive = (band == IEEE80211_BAND_2GHZ) ?
 	    IWL_PASSIVE_DWELL_BASE + IWL_PASSIVE_DWELL_TIME_24 :
 	    IWL_PASSIVE_DWELL_BASE + IWL_PASSIVE_DWELL_TIME_52;
 
@@ -358,15 +369,12 @@ static u16 iwl_get_passive_dwell_time(struct iwl_priv *priv,
 		passive = (passive * 98) / 100 - IWL_CHANNEL_TUNE_TIME * 2;
 	}
 
-	if (passive <= active)
-		passive = active + 1;
-
 	return passive;
 }
 
 static int iwl_get_channels_for_scan(struct iwl_priv *priv,
 				     enum ieee80211_band band,
-				     u8 is_active, u8 direct_mask,
+				     u8 is_active, u8 n_probes,
 				     struct iwl_scan_channel *scan_ch)
 {
 	const struct ieee80211_channel *channels = NULL;
@@ -375,6 +383,7 @@ static int iwl_get_channels_for_scan(struct iwl_priv *priv,
 	u16 passive_dwell = 0;
 	u16 active_dwell = 0;
 	int added, i;
+	u16 channel;
 
 	sband = iwl_get_hw_mode(priv, band);
 	if (!sband)
@@ -382,31 +391,35 @@ static int iwl_get_channels_for_scan(struct iwl_priv *priv,
 
 	channels = sband->channels;
 
-	active_dwell = iwl_get_active_dwell_time(priv, band);
+	active_dwell = iwl_get_active_dwell_time(priv, band, n_probes);
 	passive_dwell = iwl_get_passive_dwell_time(priv, band);
 
+	if (passive_dwell <= active_dwell)
+		passive_dwell = active_dwell + 1;
+
 	for (i = 0, added = 0; i < sband->n_channels; i++) {
 		if (channels[i].flags & IEEE80211_CHAN_DISABLED)
 			continue;
 
-		scan_ch->channel =
+		channel =
 			ieee80211_frequency_to_channel(channels[i].center_freq);
+		scan_ch->channel = cpu_to_le16(channel);
 
-		ch_info = iwl_get_channel_info(priv, band, scan_ch->channel);
+		ch_info = iwl_get_channel_info(priv, band, channel);
 		if (!is_channel_valid(ch_info)) {
 			IWL_DEBUG_SCAN("Channel %d is INVALID for this band.\n",
-				       scan_ch->channel);
+					channel);
 			continue;
 		}
 
 		if (!is_active || is_channel_passive(ch_info) ||
 		    (channels[i].flags & IEEE80211_CHAN_PASSIVE_SCAN))
-			scan_ch->type = 0;
+			scan_ch->type = SCAN_CHANNEL_TYPE_PASSIVE;
 		else
-			scan_ch->type = 1;
+			scan_ch->type = SCAN_CHANNEL_TYPE_ACTIVE;
 
-		if (scan_ch->type & 1)
-			scan_ch->type |= (direct_mask << 1);
+		if ((scan_ch->type & SCAN_CHANNEL_TYPE_ACTIVE) && n_probes)
+			scan_ch->type |= IWL_SCAN_PROBE_MASK(n_probes);
 
 		scan_ch->active_dwell = cpu_to_le16(active_dwell);
 		scan_ch->passive_dwell = cpu_to_le16(passive_dwell);
@@ -414,20 +427,20 @@ static int iwl_get_channels_for_scan(struct iwl_priv *priv,
 		/* Set txpower levels to defaults */
 		scan_ch->dsp_atten = 110;
 
+		/* NOTE: if we were doing 6Mb OFDM for scans we'd use
+		 * power level:
+		 * scan_ch->tx_gain = ((1 << 5) | (2 << 3)) | 3;
+		 */
 		if (band == IEEE80211_BAND_5GHZ)
 			scan_ch->tx_gain = ((1 << 5) | (3 << 3)) | 3;
-		else {
+		else
 			scan_ch->tx_gain = ((1 << 5) | (5 << 3));
-			/* NOTE: if we were doing 6Mb OFDM for scans we'd use
-			 * power level:
-			 * scan_ch->tx_gain = ((1 << 5) | (2 << 3)) | 3;
-			 */
-		}
 
-		IWL_DEBUG_SCAN("Scanning %d [%s %d]\n",
-			       scan_ch->channel,
-			       (scan_ch->type & 1) ? "ACTIVE" : "PASSIVE",
-			       (scan_ch->type & 1) ?
+		IWL_DEBUG_SCAN("Scanning ch=%d prob=0x%X [%s %d]\n",
+			       channel, le32_to_cpu(scan_ch->type),
+			       (scan_ch->type & SCAN_CHANNEL_TYPE_ACTIVE) ?
+				"ACTIVE" : "PASSIVE",
+			       (scan_ch->type & SCAN_CHANNEL_TYPE_ACTIVE) ?
 			       active_dwell : passive_dwell);
 
 		scan_ch++;
@@ -673,7 +686,7 @@ static u32 iwl_scan_tx_ant(struct iwl_priv *priv, enum ieee80211_band band)
 			break;
 		}
 	}
-
+	IWL_DEBUG_SCAN("select TX ANT = %c\n", 'A' + ind);
 	return scan_tx_ant[ind];
 }
 
@@ -693,7 +706,7 @@ static void iwl_bg_request_scan(struct work_struct *data)
 	u32 tx_ant;
 	u16 cmd_len;
 	enum ieee80211_band band;
-	u8 direct_mask;
+	u8 n_probes = 2;
 	u8 rx_chain = 0x7; /* bitmap: ABC chains */
 
 	conf = ieee80211_get_hw_conf(priv->hw);
@@ -793,17 +806,16 @@ static void iwl_bg_request_scan(struct work_struct *data)
 		scan->direct_scan[0].len = priv->direct_ssid_len;
 		memcpy(scan->direct_scan[0].ssid,
 		       priv->direct_ssid, priv->direct_ssid_len);
-		direct_mask = 1;
+		n_probes++;
 	} else if (!iwl_is_associated(priv) && priv->essid_len) {
 		IWL_DEBUG_SCAN("Start direct scan for '%s' (not associated)\n",
 				iwl_escape_essid(priv->essid, priv->essid_len));
 		scan->direct_scan[0].id = WLAN_EID_SSID;
 		scan->direct_scan[0].len = priv->essid_len;
 		memcpy(scan->direct_scan[0].ssid, priv->essid, priv->essid_len);
-		direct_mask = 1;
+		n_probes++;
 	} else {
 		IWL_DEBUG_SCAN("Start indirect scan.\n");
-		direct_mask = 0;
 	}
 
 	scan->tx_cmd.tx_flags = TX_CMD_FLG_SEQ_CTL_MSK;
@@ -860,16 +872,11 @@ static void iwl_bg_request_scan(struct work_struct *data)
 	scan->filter_flags |= (RXON_FILTER_ACCEPT_GRP_MSK |
 			       RXON_FILTER_BCON_AWARE_MSK);
 
-	if (direct_mask)
-		scan->channel_count =
-			iwl_get_channels_for_scan(priv, band, 1, /* active */
-						  direct_mask,
-				(void *)&scan->data[le16_to_cpu(scan->tx_cmd.len)]);
-	else
-		scan->channel_count =
-			iwl_get_channels_for_scan(priv, band, 0, /* passive */
-						  direct_mask,
-				(void *)&scan->data[le16_to_cpu(scan->tx_cmd.len)]);
+	scan->channel_count =
+		iwl_get_channels_for_scan(priv, band, 1, /* active */
+			n_probes,
+			(void *)&scan->data[le16_to_cpu(scan->tx_cmd.len)]);
+
 	if (scan->channel_count == 0) {
 		IWL_DEBUG_SCAN("channel count %d\n", scan->channel_count);
 		goto done;
diff --git a/drivers/net/wireless/iwlwifi/iwl-tx.c b/drivers/net/wireless/iwlwifi/iwl-tx.c
index 0be2a71990b0..9b50b1052b09 100644
--- a/drivers/net/wireless/iwlwifi/iwl-tx.c
+++ b/drivers/net/wireless/iwlwifi/iwl-tx.c
@@ -601,13 +601,7 @@ static void iwl_tx_cmd_build_basic(struct iwl_priv *priv,
 		tx_flags |= TX_CMD_FLG_SEQ_CTL_MSK;
 	}
 
-	if (info->flags & IEEE80211_TX_CTL_USE_RTS_CTS) {
-		tx_flags |= TX_CMD_FLG_RTS_MSK;
-		tx_flags &= ~TX_CMD_FLG_CTS_MSK;
-	} else if (info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT) {
-		tx_flags &= ~TX_CMD_FLG_RTS_MSK;
-		tx_flags |= TX_CMD_FLG_CTS_MSK;
-	}
+	priv->cfg->ops->utils->rts_tx_cmd_flag(info, &tx_flags);
 
 	if ((tx_flags & TX_CMD_FLG_RTS_MSK) || (tx_flags & TX_CMD_FLG_CTS_MSK))
 		tx_flags |= TX_CMD_FLG_FULL_TXOP_PROT_MSK;
diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c
index 1a7d18fea89d..4a22d3fba75b 100644
--- a/drivers/net/wireless/iwlwifi/iwl3945-base.c
+++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c
@@ -2035,36 +2035,6 @@ static int iwl3945_send_power_mode(struct iwl3945_priv *priv, u32 mode)
 	return rc;
 }
 
-int iwl3945_is_network_packet(struct iwl3945_priv *priv, struct ieee80211_hdr *header)
-{
-	/* Filter incoming packets to determine if they are targeted toward
-	 * this network, discarding packets coming from ourselves */
-	switch (priv->iw_mode) {
-	case IEEE80211_IF_TYPE_IBSS: /* Header: Dest. | Source    | BSSID */
-		/* packets from our adapter are dropped (echo) */
-		if (!compare_ether_addr(header->addr2, priv->mac_addr))
-			return 0;
-		/* {broad,multi}cast packets to our IBSS go through */
-		if (is_multicast_ether_addr(header->addr1))
-			return !compare_ether_addr(header->addr3, priv->bssid);
-		/* packets to our adapter go through */
-		return !compare_ether_addr(header->addr1, priv->mac_addr);
-	case IEEE80211_IF_TYPE_STA: /* Header: Dest. | AP{BSSID} | Source */
-		/* packets from our adapter are dropped (echo) */
-		if (!compare_ether_addr(header->addr3, priv->mac_addr))
-			return 0;
-		/* {broad,multi}cast packets to our BSS go through */
-		if (is_multicast_ether_addr(header->addr1))
-			return !compare_ether_addr(header->addr2, priv->bssid);
-		/* packets to our adapter go through */
-		return !compare_ether_addr(header->addr1, priv->mac_addr);
-	default:
-		return 1;
-	}
-
-	return 1;
-}
-
 /**
  * iwl3945_scan_cancel - Cancel any currently executing HW scan
  *
@@ -2117,20 +2087,6 @@ static int iwl3945_scan_cancel_timeout(struct iwl3945_priv *priv, unsigned long
 	return ret;
 }
 
-static void iwl3945_sequence_reset(struct iwl3945_priv *priv)
-{
-	/* Reset ieee stats */
-
-	/* We don't reset the net_device_stats (ieee->stats) on
-	 * re-association */
-
-	priv->last_seq_num = -1;
-	priv->last_frag_num = -1;
-	priv->last_packet_time = 0;
-
-	iwl3945_scan_cancel(priv);
-}
-
 #define MAX_UCODE_BEACON_INTERVAL	1024
 #define INTEL_CONN_LISTEN_INTERVAL	__constant_cpu_to_le16(0xA)
 
@@ -2925,72 +2881,6 @@ void iwl3945_set_decrypted_flag(struct iwl3945_priv *priv, struct sk_buff *skb,
 	}
 }
 
-#define IWL_PACKET_RETRY_TIME HZ
-
-int iwl3945_is_duplicate_packet(struct iwl3945_priv *priv, struct ieee80211_hdr *header)
-{
-	u16 sc = le16_to_cpu(header->seq_ctrl);
-	u16 seq = (sc & IEEE80211_SCTL_SEQ) >> 4;
-	u16 frag = sc & IEEE80211_SCTL_FRAG;
-	u16 *last_seq, *last_frag;
-	unsigned long *last_time;
-
-	switch (priv->iw_mode) {
-	case IEEE80211_IF_TYPE_IBSS:{
-		struct list_head *p;
-		struct iwl3945_ibss_seq *entry = NULL;
-		u8 *mac = header->addr2;
-		int index = mac[5] & (IWL_IBSS_MAC_HASH_SIZE - 1);
-
-		__list_for_each(p, &priv->ibss_mac_hash[index]) {
-			entry = list_entry(p, struct iwl3945_ibss_seq, list);
-			if (!compare_ether_addr(entry->mac, mac))
-				break;
-		}
-		if (p == &priv->ibss_mac_hash[index]) {
-			entry = kzalloc(sizeof(*entry), GFP_ATOMIC);
-			if (!entry) {
-				IWL_ERROR("Cannot malloc new mac entry\n");
-				return 0;
-			}
-			memcpy(entry->mac, mac, ETH_ALEN);
-			entry->seq_num = seq;
-			entry->frag_num = frag;
-			entry->packet_time = jiffies;
-			list_add(&entry->list, &priv->ibss_mac_hash[index]);
-			return 0;
-		}
-		last_seq = &entry->seq_num;
-		last_frag = &entry->frag_num;
-		last_time = &entry->packet_time;
-		break;
-	}
-	case IEEE80211_IF_TYPE_STA:
-		last_seq = &priv->last_seq_num;
-		last_frag = &priv->last_frag_num;
-		last_time = &priv->last_packet_time;
-		break;
-	default:
-		return 0;
-	}
-	if ((*last_seq == seq) &&
-	    time_after(*last_time + IWL_PACKET_RETRY_TIME, jiffies)) {
-		if (*last_frag == frag)
-			goto drop;
-		if (*last_frag + 1 != frag)
-			/* out-of-order fragment */
-			goto drop;
-	} else
-		*last_seq = seq;
-
-	*last_frag = frag;
-	*last_time = jiffies;
-	return 0;
-
- drop:
-	return 1;
-}
-
 #ifdef CONFIG_IWL3945_SPECTRUM_MEASUREMENT
 
 #include "iwl-spectrum.h"
@@ -6531,8 +6421,6 @@ static void iwl3945_bg_post_associate(struct work_struct *data)
 		break;
 	}
 
-	iwl3945_sequence_reset(priv);
-
 	iwl3945_activate_qos(priv, 0);
 
 	/* we have just associated, don't start scan too early */
@@ -6907,6 +6795,9 @@ static void iwl3945_config_ap(struct iwl3945_priv *priv)
 	 * clear sta table, add BCAST sta... */
 }
 
+/* temporary */
+static int iwl3945_mac_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb);
+
 static int iwl3945_mac_config_interface(struct ieee80211_hw *hw,
 					struct ieee80211_vif *vif,
 				    struct ieee80211_if_conf *conf)
@@ -6924,10 +6815,21 @@ static int iwl3945_mac_config_interface(struct ieee80211_hw *hw,
 		return 0;
 	}
 
+	/* handle this temporarily here */
+	if (priv->iw_mode == IEEE80211_IF_TYPE_IBSS &&
+	    conf->changed & IEEE80211_IFCC_BEACON) {
+		struct sk_buff *beacon = ieee80211_beacon_get(hw, vif);
+		if (!beacon)
+			return -ENOMEM;
+		rc = iwl3945_mac_beacon_update(hw, beacon);
+		if (rc)
+			return rc;
+	}
+
 	/* XXX: this MUST use conf->mac_addr */
 
 	if ((priv->iw_mode == IEEE80211_IF_TYPE_AP) &&
-	    (!conf->beacon || !conf->ssid_len)) {
+	    (!conf->ssid_len)) {
 		IWL_DEBUG_MAC80211
 		    ("Leaving in AP mode because HostAPD is not ready.\n");
 		return 0;
@@ -6959,7 +6861,7 @@ static int iwl3945_mac_config_interface(struct ieee80211_hw *hw,
 		if (priv->ibss_beacon)
 			dev_kfree_skb(priv->ibss_beacon);
 
-		priv->ibss_beacon = conf->beacon;
+		priv->ibss_beacon = ieee80211_beacon_get(hw, vif);
 	}
 
 	if (iwl3945_is_rfkill(priv))
@@ -7940,7 +7842,6 @@ static struct ieee80211_ops iwl3945_hw_ops = {
 	.conf_tx = iwl3945_mac_conf_tx,
 	.get_tsf = iwl3945_mac_get_tsf,
 	.reset_tsf = iwl3945_mac_reset_tsf,
-	.beacon_update = iwl3945_mac_beacon_update,
 	.hw_scan = iwl3945_mac_hw_scan
 };
 
@@ -7950,7 +7851,6 @@ static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e
 	struct iwl3945_priv *priv;
 	struct ieee80211_hw *hw;
 	struct iwl_3945_cfg *cfg = (struct iwl_3945_cfg *)(ent->driver_data);
-	int i;
 	unsigned long flags;
 	DECLARE_MAC_BUF(mac);
 
@@ -8011,9 +7911,6 @@ static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e
 	spin_lock_init(&priv->sta_lock);
 	spin_lock_init(&priv->hcmd_lock);
 
-	for (i = 0; i < IWL_IBSS_MAC_HASH_SIZE; i++)
-		INIT_LIST_HEAD(&priv->ibss_mac_hash[i]);
-
 	INIT_LIST_HEAD(&priv->free_frames);
 
 	mutex_init(&priv->mutex);
@@ -8186,8 +8083,6 @@ static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e
 static void __devexit iwl3945_pci_remove(struct pci_dev *pdev)
 {
 	struct iwl3945_priv *priv = pci_get_drvdata(pdev);
-	struct list_head *p, *q;
-	int i;
 	unsigned long flags;
 
 	if (!priv)
@@ -8208,14 +8103,6 @@ static void __devexit iwl3945_pci_remove(struct pci_dev *pdev)
 
 	iwl_synchronize_irq(priv);
 
-	/* Free MAC hash list for ADHOC */
-	for (i = 0; i < IWL_IBSS_MAC_HASH_SIZE; i++) {
-		list_for_each_safe(p, q, &priv->ibss_mac_hash[i]) {
-			list_del(p);
-			kfree(list_entry(p, struct iwl3945_ibss_seq, list));
-		}
-	}
-
 	sysfs_remove_group(&pdev->dev.kobj, &iwl3945_attribute_group);
 
 	iwl3945_rfkill_unregister(priv);
diff --git a/drivers/net/wireless/iwlwifi/iwl4965-base.c b/drivers/net/wireless/iwlwifi/iwl4965-base.c
index 7f65d9123b2a..71f5da3fe5c4 100644
--- a/drivers/net/wireless/iwlwifi/iwl4965-base.c
+++ b/drivers/net/wireless/iwlwifi/iwl4965-base.c
@@ -250,6 +250,9 @@ static int iwl4965_commit_rxon(struct iwl_priv *priv)
 
 	/* always get timestamp with Rx frame */
 	priv->staging_rxon.flags |= RXON_FLG_TSF2HOST_MSK;
+	/* allow CTS-to-self if possible. this is relevant only for
+	 * 5000, but will not damage 4965 */
+	priv->staging_rxon.flags |= RXON_FLG_SELF_CTS_EN;
 
 	ret = iwl4965_check_rxon_cmd(&priv->staging_rxon);
 	if (ret) {
@@ -325,16 +328,6 @@ static int iwl4965_commit_rxon(struct iwl_priv *priv)
 	if (!priv->error_recovering)
 		priv->start_calib = 0;
 
-	iwl_init_sensitivity(priv);
-
-	/* If we issue a new RXON command which required a tune then we must
-	 * send a new TXPOWER command or we won't be able to Tx any frames */
-	ret = iwl_set_tx_power(priv, priv->tx_power_user_lmt, true);
-	if (ret) {
-		IWL_ERROR("Error sending TX power (%d)\n", ret);
-		return ret;
-	}
-
 	/* Add the broadcast address so we can send broadcast frames */
 	if (iwl_rxon_add_station(priv, iwl_bcast_addr, 0) ==
 						IWL_INVALID_STATION) {
@@ -370,6 +363,16 @@ static int iwl4965_commit_rxon(struct iwl_priv *priv)
 		memcpy(active_rxon, &priv->staging_rxon, sizeof(*active_rxon));
 	}
 
+	iwl_init_sensitivity(priv);
+
+	/* If we issue a new RXON command which required a tune then we must
+	 * send a new TXPOWER command or we won't be able to Tx any frames */
+	ret = iwl_set_tx_power(priv, priv->tx_power_user_lmt, true);
+	if (ret) {
+		IWL_ERROR("Error sending TX power (%d)\n", ret);
+		return ret;
+	}
+
 	return 0;
 }
 
@@ -572,25 +575,14 @@ static void iwl4965_ht_conf(struct iwl_priv *priv,
 /*
  * QoS  support
 */
-static int iwl4965_send_qos_params_command(struct iwl_priv *priv,
-				       struct iwl4965_qosparam_cmd *qos)
-{
-
-	return iwl_send_cmd_pdu(priv, REPLY_QOS_PARAM,
-				sizeof(struct iwl4965_qosparam_cmd), qos);
-}
-
-static void iwl4965_activate_qos(struct iwl_priv *priv, u8 force)
+static void iwl_activate_qos(struct iwl_priv *priv, u8 force)
 {
-	unsigned long flags;
-
 	if (test_bit(STATUS_EXIT_PENDING, &priv->status))
 		return;
 
 	if (!priv->qos_data.qos_enable)
 		return;
 
-	spin_lock_irqsave(&priv->lock, flags);
 	priv->qos_data.def_qos_parm.qos_flags = 0;
 
 	if (priv->qos_data.qos_cap.q_AP.queue_request &&
@@ -604,15 +596,14 @@ static void iwl4965_activate_qos(struct iwl_priv *priv, u8 force)
 	if (priv->current_ht_config.is_ht)
 		priv->qos_data.def_qos_parm.qos_flags |= QOS_PARAM_FLG_TGN_MSK;
 
-	spin_unlock_irqrestore(&priv->lock, flags);
-
 	if (force || iwl_is_associated(priv)) {
 		IWL_DEBUG_QOS("send QoS cmd with Qos active=%d FLAGS=0x%X\n",
 				priv->qos_data.qos_active,
 				priv->qos_data.def_qos_parm.qos_flags);
 
-		iwl4965_send_qos_params_command(priv,
-				&(priv->qos_data.def_qos_parm));
+		iwl_send_cmd_pdu_async(priv, REPLY_QOS_PARAM,
+				       sizeof(struct iwl_qosparam_cmd),
+				       &priv->qos_data.def_qos_parm, NULL);
 	}
 }
 
@@ -2421,6 +2412,7 @@ static void iwl4965_post_associate(struct iwl_priv *priv)
 	struct ieee80211_conf *conf = NULL;
 	int ret = 0;
 	DECLARE_MAC_BUF(mac);
+	unsigned long flags;
 
 	if (priv->iw_mode == IEEE80211_IF_TYPE_AP) {
 		IWL_ERROR("%s Should not be called in AP mode\n", __FUNCTION__);
@@ -2510,25 +2502,15 @@ static void iwl4965_post_associate(struct iwl_priv *priv)
 	if (priv->iw_mode == IEEE80211_IF_TYPE_IBSS)
 		priv->assoc_station_added = 1;
 
-	iwl4965_activate_qos(priv, 0);
+	spin_lock_irqsave(&priv->lock, flags);
+	iwl_activate_qos(priv, 0);
+	spin_unlock_irqrestore(&priv->lock, flags);
 
 	iwl_power_update_mode(priv, 0);
 	/* we have just associated, don't start scan too early */
 	priv->next_scan_jiffies = jiffies + IWL_DELAY_NEXT_SCAN;
 }
 
-
-static void iwl4965_bg_post_associate(struct work_struct *data)
-{
-	struct iwl_priv *priv = container_of(data, struct iwl_priv,
-					     post_associate.work);
-
-	mutex_lock(&priv->mutex);
-	iwl4965_post_associate(priv);
-	mutex_unlock(&priv->mutex);
-
-}
-
 static int iwl4965_mac_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf);
 
 static void iwl_bg_scan_completed(struct work_struct *work)
@@ -2659,7 +2641,6 @@ static void iwl4965_mac_stop(struct ieee80211_hw *hw)
 		 */
 		mutex_lock(&priv->mutex);
 		iwl_scan_cancel_timeout(priv, 100);
-		cancel_delayed_work(&priv->post_associate);
 		mutex_unlock(&priv->mutex);
 	}
 
@@ -2855,6 +2836,7 @@ out:
 static void iwl4965_config_ap(struct iwl_priv *priv)
 {
 	int ret = 0;
+	unsigned long flags;
 
 	if (test_bit(STATUS_EXIT_PENDING, &priv->status))
 		return;
@@ -2902,7 +2884,9 @@ static void iwl4965_config_ap(struct iwl_priv *priv)
 		/* restore RXON assoc */
 		priv->staging_rxon.filter_flags |= RXON_FILTER_ASSOC_MSK;
 		iwl4965_commit_rxon(priv);
-		iwl4965_activate_qos(priv, 1);
+		spin_lock_irqsave(&priv->lock, flags);
+		iwl_activate_qos(priv, 1);
+		spin_unlock_irqrestore(&priv->lock, flags);
 		iwl_rxon_add_station(priv, iwl_bcast_addr, 0);
 	}
 	iwl4965_send_beacon_cmd(priv);
@@ -2912,6 +2896,9 @@ static void iwl4965_config_ap(struct iwl_priv *priv)
 	 * clear sta table, add BCAST sta... */
 }
 
+/* temporary */
+static int iwl4965_mac_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb);
+
 static int iwl4965_mac_config_interface(struct ieee80211_hw *hw,
 					struct ieee80211_vif *vif,
 				    struct ieee80211_if_conf *conf)
@@ -2929,8 +2916,18 @@ static int iwl4965_mac_config_interface(struct ieee80211_hw *hw,
 		return 0;
 	}
 
+	if (priv->iw_mode == IEEE80211_IF_TYPE_IBSS &&
+	    conf->changed & IEEE80211_IFCC_BEACON) {
+		struct sk_buff *beacon = ieee80211_beacon_get(hw, vif);
+		if (!beacon)
+			return -ENOMEM;
+		rc = iwl4965_mac_beacon_update(hw, beacon);
+		if (rc)
+			return rc;
+	}
+
 	if ((priv->iw_mode == IEEE80211_IF_TYPE_AP) &&
-	    (!conf->beacon || !conf->ssid_len)) {
+	    (!conf->ssid_len)) {
 		IWL_DEBUG_MAC80211
 		    ("Leaving in AP mode because HostAPD is not ready.\n");
 		return 0;
@@ -2962,7 +2959,7 @@ static int iwl4965_mac_config_interface(struct ieee80211_hw *hw,
 		if (priv->ibss_beacon)
 			dev_kfree_skb(priv->ibss_beacon);
 
-		priv->ibss_beacon = conf->beacon;
+		priv->ibss_beacon = ieee80211_beacon_get(hw, vif);
 	}
 
 	if (iwl_is_rfkill(priv))
@@ -3048,7 +3045,6 @@ static void iwl4965_mac_remove_interface(struct ieee80211_hw *hw,
 
 	if (iwl_is_ready_rf(priv)) {
 		iwl_scan_cancel_timeout(priv, 100);
-		cancel_delayed_work(&priv->post_associate);
 		priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
 		iwl4965_commit_rxon(priv);
 	}
@@ -3338,15 +3334,12 @@ static int iwl4965_mac_conf_tx(struct ieee80211_hw *hw, u16 queue,
 	priv->qos_data.def_qos_parm.ac[q].reserved1 = 0;
 	priv->qos_data.qos_active = 1;
 
-	spin_unlock_irqrestore(&priv->lock, flags);
-
-	mutex_lock(&priv->mutex);
 	if (priv->iw_mode == IEEE80211_IF_TYPE_AP)
-		iwl4965_activate_qos(priv, 1);
+		iwl_activate_qos(priv, 1);
 	else if (priv->assoc_id && iwl_is_associated(priv))
-		iwl4965_activate_qos(priv, 0);
+		iwl_activate_qos(priv, 0);
 
-	mutex_unlock(&priv->mutex);
+	spin_unlock_irqrestore(&priv->lock, flags);
 
 	IWL_DEBUG_MAC80211("leave\n");
 	return 0;
@@ -3413,8 +3406,6 @@ static void iwl4965_mac_reset_tsf(struct ieee80211_hw *hw)
 
 	iwl_reset_qos(priv);
 
-	cancel_delayed_work(&priv->post_associate);
-
 	spin_lock_irqsave(&priv->lock, flags);
 	priv->assoc_id = 0;
 	priv->assoc_capability = 0;
@@ -4016,7 +4007,6 @@ static void iwl_setup_deferred_work(struct iwl_priv *priv)
 	INIT_WORK(&priv->beacon_update, iwl4965_bg_beacon_update);
 	INIT_WORK(&priv->set_monitor, iwl4965_bg_set_monitor);
 	INIT_WORK(&priv->run_time_calib_work, iwl_bg_run_time_calib_work);
-	INIT_DELAYED_WORK(&priv->post_associate, iwl4965_bg_post_associate);
 	INIT_DELAYED_WORK(&priv->init_alive_start, iwl_bg_init_alive_start);
 	INIT_DELAYED_WORK(&priv->alive_start, iwl_bg_alive_start);
 
@@ -4043,7 +4033,6 @@ static void iwl_cancel_deferred_work(struct iwl_priv *priv)
 	cancel_delayed_work_sync(&priv->init_alive_start);
 	cancel_delayed_work(&priv->scan_check);
 	cancel_delayed_work(&priv->alive_start);
-	cancel_delayed_work(&priv->post_associate);
 	cancel_work_sync(&priv->beacon_update);
 	del_timer_sync(&priv->statistics_periodic);
 }
@@ -4090,7 +4079,6 @@ static struct ieee80211_ops iwl4965_hw_ops = {
 	.get_tx_stats = iwl4965_mac_get_tx_stats,
 	.conf_tx = iwl4965_mac_conf_tx,
 	.reset_tsf = iwl4965_mac_reset_tsf,
-	.beacon_update = iwl4965_mac_beacon_update,
 	.bss_info_changed = iwl4965_bss_info_changed,
 	.ampdu_action = iwl4965_mac_ampdu_action,
 	.hw_scan = iwl4965_mac_hw_scan
@@ -4409,8 +4397,16 @@ static struct pci_device_id iwl_hw_card_ids[] = {
 	{IWL_PCI_DEVICE(0x4229, PCI_ANY_ID, iwl4965_agn_cfg)},
 	{IWL_PCI_DEVICE(0x4230, PCI_ANY_ID, iwl4965_agn_cfg)},
 #ifdef CONFIG_IWL5000
-	{IWL_PCI_DEVICE(0x4235, PCI_ANY_ID, iwl5300_agn_cfg)},
+	{IWL_PCI_DEVICE(0x4232, 0x1205, iwl5100_bg_cfg)},
+	{IWL_PCI_DEVICE(0x4232, 0x1305, iwl5100_bg_cfg)},
+	{IWL_PCI_DEVICE(0x4232, 0x1206, iwl5100_abg_cfg)},
+	{IWL_PCI_DEVICE(0x4232, 0x1306, iwl5100_abg_cfg)},
+	{IWL_PCI_DEVICE(0x4232, 0x1326, iwl5100_abg_cfg)},
+	{IWL_PCI_DEVICE(0x4237, 0x1216, iwl5100_abg_cfg)},
 	{IWL_PCI_DEVICE(0x4232, PCI_ANY_ID, iwl5100_agn_cfg)},
+	{IWL_PCI_DEVICE(0x4235, PCI_ANY_ID, iwl5300_agn_cfg)},
+	{IWL_PCI_DEVICE(0x4236, PCI_ANY_ID, iwl5300_agn_cfg)},
+	{IWL_PCI_DEVICE(0x4237, PCI_ANY_ID, iwl5100_agn_cfg)},
 	{IWL_PCI_DEVICE(0x423A, PCI_ANY_ID, iwl5350_agn_cfg)},
 #endif /* CONFIG_IWL5000 */
 	{0}
diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c
index 5d30c57e3969..913dc9fe08f9 100644
--- a/drivers/net/wireless/mac80211_hwsim.c
+++ b/drivers/net/wireless/mac80211_hwsim.c
@@ -126,7 +126,7 @@ static void mac80211_hwsim_monitor_rx(struct ieee80211_hw *hw,
 					  (1 << IEEE80211_RADIOTAP_CHANNEL));
 	hdr->rt_flags = 0;
 	hdr->rt_rate = txrate->bitrate / 5;
-	hdr->rt_channel = data->channel->center_freq;
+	hdr->rt_channel = cpu_to_le16(data->channel->center_freq);
 	flags = IEEE80211_CHAN_2GHZ;
 	if (txrate->flags & IEEE80211_RATE_ERP_G)
 		flags |= IEEE80211_CHAN_OFDM;
diff --git a/drivers/net/wireless/rt2x00/rt2400pci.c b/drivers/net/wireless/rt2x00/rt2400pci.c
index 91cbd9e560bd..4c0538d6099b 100644
--- a/drivers/net/wireless/rt2x00/rt2400pci.c
+++ b/drivers/net/wireless/rt2x00/rt2400pci.c
@@ -1069,6 +1069,40 @@ static void rt2400pci_write_tx_desc(struct rt2x00_dev *rt2x00dev,
 /*
  * TX data initialization
  */
+static void rt2400pci_write_beacon(struct queue_entry *entry)
+{
+	struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
+	struct queue_entry_priv_pci *entry_priv = entry->priv_data;
+	struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb);
+	u32 word;
+	u32 reg;
+
+	/*
+	 * Disable beaconing while we are reloading the beacon data,
+	 * otherwise we might be sending out invalid data.
+	 */
+	rt2x00pci_register_read(rt2x00dev, CSR14, &reg);
+	rt2x00_set_field32(&reg, CSR14_TSF_COUNT, 0);
+	rt2x00_set_field32(&reg, CSR14_TBCN, 0);
+	rt2x00_set_field32(&reg, CSR14_BEACON_GEN, 0);
+	rt2x00pci_register_write(rt2x00dev, CSR14, reg);
+
+	/*
+	 * Replace rt2x00lib allocated descriptor with the
+	 * pointer to the _real_ hardware descriptor.
+	 * After that, map the beacon to DMA and update the
+	 * descriptor.
+	 */
+	memcpy(entry_priv->desc, skbdesc->desc, skbdesc->desc_len);
+	skbdesc->desc = entry_priv->desc;
+
+	rt2x00queue_map_txskb(rt2x00dev, entry->skb);
+
+	rt2x00_desc_read(entry_priv->desc, 1, &word);
+	rt2x00_set_field32(&word, TXD_W1_BUFFER_ADDRESS, skbdesc->skb_dma);
+	rt2x00_desc_write(entry_priv->desc, 1, word);
+}
+
 static void rt2400pci_kick_tx_queue(struct rt2x00_dev *rt2x00dev,
 				    const enum data_queue_qid queue)
 {
@@ -1515,59 +1549,6 @@ static u64 rt2400pci_get_tsf(struct ieee80211_hw *hw)
 	return tsf;
 }
 
-static int rt2400pci_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb)
-{
-	struct rt2x00_dev *rt2x00dev = hw->priv;
-	struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
-	struct rt2x00_intf *intf = vif_to_intf(tx_info->control.vif);
-	struct queue_entry_priv_pci *entry_priv;
-	struct skb_frame_desc *skbdesc;
-	struct txentry_desc txdesc;
-	u32 reg;
-
-	if (unlikely(!intf->beacon))
-		return -ENOBUFS;
-	entry_priv = intf->beacon->priv_data;
-
-	/*
-	 * Copy all TX descriptor information into txdesc,
-	 * after that we are free to use the skb->cb array
-	 * for our information.
-	 */
-	intf->beacon->skb = skb;
-	rt2x00queue_create_tx_descriptor(intf->beacon, &txdesc);
-
-	/*
-	 * Fill in skb descriptor
-	 */
-	skbdesc = get_skb_frame_desc(skb);
-	memset(skbdesc, 0, sizeof(*skbdesc));
-	skbdesc->desc = entry_priv->desc;
-	skbdesc->desc_len = intf->beacon->queue->desc_size;
-	skbdesc->entry = intf->beacon;
-
-	/*
-	 * Disable beaconing while we are reloading the beacon data,
-	 * otherwise we might be sending out invalid data.
-	 */
-	rt2x00pci_register_read(rt2x00dev, CSR14, &reg);
-	rt2x00_set_field32(&reg, CSR14_TSF_COUNT, 0);
-	rt2x00_set_field32(&reg, CSR14_TBCN, 0);
-	rt2x00_set_field32(&reg, CSR14_BEACON_GEN, 0);
-	rt2x00pci_register_write(rt2x00dev, CSR14, reg);
-
-	/*
-	 * Enable beacon generation.
-	 * Write entire beacon with descriptor to register,
-	 * and kick the beacon generator.
-	 */
-	rt2x00queue_map_txskb(rt2x00dev, intf->beacon->skb);
-	rt2x00queue_write_tx_descriptor(intf->beacon, &txdesc);
-	rt2x00dev->ops->lib->kick_tx_queue(rt2x00dev, QID_BEACON);
-
-	return 0;
-}
-
 static int rt2400pci_tx_last_beacon(struct ieee80211_hw *hw)
 {
 	struct rt2x00_dev *rt2x00dev = hw->priv;
@@ -1592,7 +1573,6 @@ static const struct ieee80211_ops rt2400pci_mac80211_ops = {
 	.conf_tx		= rt2400pci_conf_tx,
 	.get_tx_stats		= rt2x00mac_get_tx_stats,
 	.get_tsf		= rt2400pci_get_tsf,
-	.beacon_update		= rt2400pci_beacon_update,
 	.tx_last_beacon		= rt2400pci_tx_last_beacon,
 };
 
@@ -1610,6 +1590,7 @@ static const struct rt2x00lib_ops rt2400pci_rt2x00_ops = {
 	.link_tuner		= rt2400pci_link_tuner,
 	.write_tx_desc		= rt2400pci_write_tx_desc,
 	.write_tx_data		= rt2x00pci_write_tx_data,
+	.write_beacon		= rt2400pci_write_beacon,
 	.kick_tx_queue		= rt2400pci_kick_tx_queue,
 	.fill_rxdone		= rt2400pci_fill_rxdone,
 	.config_filter		= rt2400pci_config_filter,
diff --git a/drivers/net/wireless/rt2x00/rt2500pci.c b/drivers/net/wireless/rt2x00/rt2500pci.c
index 0f2a0e22fd71..aa6dfb811c71 100644
--- a/drivers/net/wireless/rt2x00/rt2500pci.c
+++ b/drivers/net/wireless/rt2x00/rt2500pci.c
@@ -1227,6 +1227,40 @@ static void rt2500pci_write_tx_desc(struct rt2x00_dev *rt2x00dev,
 /*
  * TX data initialization
  */
+static void rt2500pci_write_beacon(struct queue_entry *entry)
+{
+	struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
+	struct queue_entry_priv_pci *entry_priv = entry->priv_data;
+	struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb);
+	u32 word;
+	u32 reg;
+
+	/*
+	 * Disable beaconing while we are reloading the beacon data,
+	 * otherwise we might be sending out invalid data.
+	 */
+	rt2x00pci_register_read(rt2x00dev, CSR14, &reg);
+	rt2x00_set_field32(&reg, CSR14_TSF_COUNT, 0);
+	rt2x00_set_field32(&reg, CSR14_TBCN, 0);
+	rt2x00_set_field32(&reg, CSR14_BEACON_GEN, 0);
+	rt2x00pci_register_write(rt2x00dev, CSR14, reg);
+
+	/*
+	 * Replace rt2x00lib allocated descriptor with the
+	 * pointer to the _real_ hardware descriptor.
+	 * After that, map the beacon to DMA and update the
+	 * descriptor.
+	 */
+	memcpy(entry_priv->desc, skbdesc->desc, skbdesc->desc_len);
+	skbdesc->desc = entry_priv->desc;
+
+	rt2x00queue_map_txskb(rt2x00dev, entry->skb);
+
+	rt2x00_desc_read(entry_priv->desc, 1, &word);
+	rt2x00_set_field32(&word, TXD_W1_BUFFER_ADDRESS, skbdesc->skb_dma);
+	rt2x00_desc_write(entry_priv->desc, 1, word);
+}
+
 static void rt2500pci_kick_tx_queue(struct rt2x00_dev *rt2x00dev,
 				    const enum data_queue_qid queue)
 {
@@ -1808,60 +1842,6 @@ static u64 rt2500pci_get_tsf(struct ieee80211_hw *hw)
 	return tsf;
 }
 
-static int rt2500pci_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb)
-{
-	struct rt2x00_dev *rt2x00dev = hw->priv;
-	struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
-	struct rt2x00_intf *intf = vif_to_intf(tx_info->control.vif);
-	struct queue_entry_priv_pci *entry_priv;
-	struct skb_frame_desc *skbdesc;
-	struct txentry_desc txdesc;
-	u32 reg;
-
-	if (unlikely(!intf->beacon))
-		return -ENOBUFS;
-
-	entry_priv = intf->beacon->priv_data;
-
-	/*
-	 * Copy all TX descriptor information into txdesc,
-	 * after that we are free to use the skb->cb array
-	 * for our information.
-	 */
-	intf->beacon->skb = skb;
-	rt2x00queue_create_tx_descriptor(intf->beacon, &txdesc);
-
-	/*
-	 * Fill in skb descriptor
-	 */
-	skbdesc = get_skb_frame_desc(skb);
-	memset(skbdesc, 0, sizeof(*skbdesc));
-	skbdesc->desc = entry_priv->desc;
-	skbdesc->desc_len = intf->beacon->queue->desc_size;
-	skbdesc->entry = intf->beacon;
-
-	/*
-	 * Disable beaconing while we are reloading the beacon data,
-	 * otherwise we might be sending out invalid data.
-	 */
-	rt2x00pci_register_read(rt2x00dev, CSR14, &reg);
-	rt2x00_set_field32(&reg, CSR14_TSF_COUNT, 0);
-	rt2x00_set_field32(&reg, CSR14_TBCN, 0);
-	rt2x00_set_field32(&reg, CSR14_BEACON_GEN, 0);
-	rt2x00pci_register_write(rt2x00dev, CSR14, reg);
-
-	/*
-	 * Enable beacon generation.
-	 * Write entire beacon with descriptor to register,
-	 * and kick the beacon generator.
-	 */
-	rt2x00queue_map_txskb(rt2x00dev, intf->beacon->skb);
-	rt2x00queue_write_tx_descriptor(intf->beacon, &txdesc);
-	rt2x00dev->ops->lib->kick_tx_queue(rt2x00dev, QID_BEACON);
-
-	return 0;
-}
-
 static int rt2500pci_tx_last_beacon(struct ieee80211_hw *hw)
 {
 	struct rt2x00_dev *rt2x00dev = hw->priv;
@@ -1886,7 +1866,6 @@ static const struct ieee80211_ops rt2500pci_mac80211_ops = {
 	.conf_tx		= rt2x00mac_conf_tx,
 	.get_tx_stats		= rt2x00mac_get_tx_stats,
 	.get_tsf		= rt2500pci_get_tsf,
-	.beacon_update		= rt2500pci_beacon_update,
 	.tx_last_beacon		= rt2500pci_tx_last_beacon,
 };
 
@@ -1904,6 +1883,7 @@ static const struct rt2x00lib_ops rt2500pci_rt2x00_ops = {
 	.link_tuner		= rt2500pci_link_tuner,
 	.write_tx_desc		= rt2500pci_write_tx_desc,
 	.write_tx_data		= rt2x00pci_write_tx_data,
+	.write_beacon		= rt2500pci_write_beacon,
 	.kick_tx_queue		= rt2500pci_kick_tx_queue,
 	.fill_rxdone		= rt2500pci_fill_rxdone,
 	.config_filter		= rt2500pci_config_filter,
diff --git a/drivers/net/wireless/rt2x00/rt2500usb.c b/drivers/net/wireless/rt2x00/rt2500usb.c
index 367db10b96d9..3558cb210747 100644
--- a/drivers/net/wireless/rt2x00/rt2500usb.c
+++ b/drivers/net/wireless/rt2x00/rt2500usb.c
@@ -1107,6 +1107,65 @@ static void rt2500usb_write_tx_desc(struct rt2x00_dev *rt2x00dev,
 	rt2x00_desc_write(txd, 0, word);
 }
 
+/*
+ * TX data initialization
+ */
+static void rt2500usb_beacondone(struct urb *urb);
+
+static void rt2500usb_write_beacon(struct queue_entry *entry)
+{
+	struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
+	struct usb_device *usb_dev = to_usb_device_intf(rt2x00dev->dev);
+	struct queue_entry_priv_usb_bcn *bcn_priv = entry->priv_data;
+	struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb);
+	int pipe = usb_sndbulkpipe(usb_dev, 1);
+	int length;
+	u16 reg;
+
+	/*
+	 * Add the descriptor in front of the skb.
+	 */
+	skb_push(entry->skb, entry->queue->desc_size);
+	memcpy(entry->skb->data, skbdesc->desc, skbdesc->desc_len);
+	skbdesc->desc = entry->skb->data;
+
+	/*
+	 * Disable beaconing while we are reloading the beacon data,
+	 * otherwise we might be sending out invalid data.
+	 */
+	rt2500usb_register_read(rt2x00dev, TXRX_CSR19, &reg);
+	rt2x00_set_field16(&reg, TXRX_CSR19_TSF_COUNT, 0);
+	rt2x00_set_field16(&reg, TXRX_CSR19_TBCN, 0);
+	rt2x00_set_field16(&reg, TXRX_CSR19_BEACON_GEN, 0);
+	rt2500usb_register_write(rt2x00dev, TXRX_CSR19, reg);
+
+	/*
+	 * USB devices cannot blindly pass the skb->len as the
+	 * length of the data to usb_fill_bulk_urb. Pass the skb
+	 * to the driver to determine what the length should be.
+	 */
+	length = rt2x00dev->ops->lib->get_tx_data_len(rt2x00dev, entry->skb);
+
+	usb_fill_bulk_urb(bcn_priv->urb, usb_dev, pipe,
+			  entry->skb->data, length, rt2500usb_beacondone,
+			  entry);
+
+	/*
+	 * Second we need to create the guardian byte.
+	 * We only need a single byte, so lets recycle
+	 * the 'flags' field we are not using for beacons.
+	 */
+	bcn_priv->guardian_data = 0;
+	usb_fill_bulk_urb(bcn_priv->guardian_urb, usb_dev, pipe,
+			  &bcn_priv->guardian_data, 1, rt2500usb_beacondone,
+			  entry);
+
+	/*
+	 * Send out the guardian byte.
+	 */
+	usb_submit_urb(bcn_priv->guardian_urb, GFP_ATOMIC);
+}
+
 static int rt2500usb_get_tx_data_len(struct rt2x00_dev *rt2x00dev,
 				     struct sk_buff *skb)
 {
@@ -1122,9 +1181,6 @@ static int rt2500usb_get_tx_data_len(struct rt2x00_dev *rt2x00dev,
 	return length;
 }
 
-/*
- * TX data initialization
- */
 static void rt2500usb_kick_tx_queue(struct rt2x00_dev *rt2x00dev,
 				    const enum data_queue_qid queue)
 {
@@ -1679,96 +1735,6 @@ static int rt2500usb_probe_hw(struct rt2x00_dev *rt2x00dev)
 	return 0;
 }
 
-/*
- * IEEE80211 stack callback functions.
- */
-static int rt2500usb_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb)
-{
-	struct rt2x00_dev *rt2x00dev = hw->priv;
-	struct usb_device *usb_dev = to_usb_device_intf(rt2x00dev->dev);
-	struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
-	struct rt2x00_intf *intf = vif_to_intf(tx_info->control.vif);
-	struct queue_entry_priv_usb_bcn *bcn_priv;
-	struct skb_frame_desc *skbdesc;
-	struct txentry_desc txdesc;
-	int pipe = usb_sndbulkpipe(usb_dev, 1);
-	int length;
-	u16 reg;
-
-	if (unlikely(!intf->beacon))
-		return -ENOBUFS;
-
-	bcn_priv = intf->beacon->priv_data;
-
-	/*
-	 * Copy all TX descriptor information into txdesc,
-	 * after that we are free to use the skb->cb array
-	 * for our information.
-	 */
-	intf->beacon->skb = skb;
-	rt2x00queue_create_tx_descriptor(intf->beacon, &txdesc);
-
-	/*
-	 * Add the descriptor in front of the skb.
-	 */
-	skb_push(skb, intf->beacon->queue->desc_size);
-	memset(skb->data, 0, intf->beacon->queue->desc_size);
-
-	/*
-	 * Fill in skb descriptor
-	 */
-	skbdesc = get_skb_frame_desc(skb);
-	memset(skbdesc, 0, sizeof(*skbdesc));
-	skbdesc->desc = skb->data;
-	skbdesc->desc_len = intf->beacon->queue->desc_size;
-	skbdesc->entry = intf->beacon;
-
-	/*
-	 * Disable beaconing while we are reloading the beacon data,
-	 * otherwise we might be sending out invalid data.
-	 */
-	rt2500usb_register_read(rt2x00dev, TXRX_CSR19, &reg);
-	rt2x00_set_field16(&reg, TXRX_CSR19_TSF_COUNT, 0);
-	rt2x00_set_field16(&reg, TXRX_CSR19_TBCN, 0);
-	rt2x00_set_field16(&reg, TXRX_CSR19_BEACON_GEN, 0);
-	rt2500usb_register_write(rt2x00dev, TXRX_CSR19, reg);
-
-	rt2x00queue_write_tx_descriptor(intf->beacon, &txdesc);
-
-	/*
-	 * USB devices cannot blindly pass the skb->len as the
-	 * length of the data to usb_fill_bulk_urb. Pass the skb
-	 * to the driver to determine what the length should be.
-	 */
-	length = rt2500usb_get_tx_data_len(rt2x00dev, skb);
-
-	usb_fill_bulk_urb(bcn_priv->urb, usb_dev, pipe,
-			  skb->data, length, rt2500usb_beacondone,
-			  intf->beacon);
-
-	/*
-	 * Second we need to create the guardian byte.
-	 * We only need a single byte, so lets recycle
-	 * the 'flags' field we are not using for beacons.
-	 */
-	bcn_priv->guardian_data = 0;
-	usb_fill_bulk_urb(bcn_priv->guardian_urb, usb_dev, pipe,
-			  &bcn_priv->guardian_data, 1, rt2500usb_beacondone,
-			  intf->beacon);
-
-	/*
-	 * Send out the guardian byte.
-	 */
-	usb_submit_urb(bcn_priv->guardian_urb, GFP_ATOMIC);
-
-	/*
-	 * Enable beacon generation.
-	 */
-	rt2500usb_kick_tx_queue(rt2x00dev, QID_BEACON);
-
-	return 0;
-}
-
 static const struct ieee80211_ops rt2500usb_mac80211_ops = {
 	.tx			= rt2x00mac_tx,
 	.start			= rt2x00mac_start,
@@ -1782,7 +1748,6 @@ static const struct ieee80211_ops rt2500usb_mac80211_ops = {
 	.bss_info_changed	= rt2x00mac_bss_info_changed,
 	.conf_tx		= rt2x00mac_conf_tx,
 	.get_tx_stats		= rt2x00mac_get_tx_stats,
-	.beacon_update		= rt2500usb_beacon_update,
 };
 
 static const struct rt2x00lib_ops rt2500usb_rt2x00_ops = {
@@ -1797,6 +1762,7 @@ static const struct rt2x00lib_ops rt2500usb_rt2x00_ops = {
 	.link_tuner		= rt2500usb_link_tuner,
 	.write_tx_desc		= rt2500usb_write_tx_desc,
 	.write_tx_data		= rt2x00usb_write_tx_data,
+	.write_beacon		= rt2500usb_write_beacon,
 	.get_tx_data_len	= rt2500usb_get_tx_data_len,
 	.kick_tx_queue		= rt2500usb_kick_tx_queue,
 	.fill_rxdone		= rt2500usb_fill_rxdone,
diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h
index c07d9ef383f0..9fab0df18c3c 100644
--- a/drivers/net/wireless/rt2x00/rt2x00.h
+++ b/drivers/net/wireless/rt2x00/rt2x00.h
@@ -364,6 +364,8 @@ struct rt2x00_intf {
 #define DELAYED_UPDATE_BEACON		0x00000001
 #define DELAYED_CONFIG_ERP		0x00000002
 #define DELAYED_LED_ASSOC		0x00000004
+
+	u16 seqno;
 };
 
 static inline struct rt2x00_intf* vif_to_intf(struct ieee80211_vif *vif)
@@ -434,6 +436,7 @@ struct rt2x00lib_conf {
  */
 struct rt2x00lib_erp {
 	int short_preamble;
+	int cts_protection;
 
 	int ack_timeout;
 	int ack_consume_time;
@@ -520,6 +523,7 @@ struct rt2x00lib_ops {
 			       struct sk_buff *skb,
 			       struct txentry_desc *txdesc);
 	int (*write_tx_data) (struct queue_entry *entry);
+	void (*write_beacon) (struct queue_entry *entry);
 	int (*get_tx_data_len) (struct rt2x00_dev *rt2x00dev,
 				struct sk_buff *skb);
 	void (*kick_tx_queue) (struct rt2x00_dev *rt2x00dev,
@@ -910,39 +914,6 @@ static inline u16 get_duration_res(const unsigned int size, const u8 rate)
 void rt2x00queue_map_txskb(struct rt2x00_dev *rt2x00dev, struct sk_buff *skb);
 
 /**
- * rt2x00queue_create_tx_descriptor - Create TX descriptor from mac80211 input
- * @entry: The entry which will be used to transfer the TX frame.
- * @txdesc: rt2x00 TX descriptor which will be initialized by this function.
- *
- * This function will initialize the &struct txentry_desc based on information
- * from mac80211. This descriptor can then be used by rt2x00lib and the drivers
- * to correctly initialize the hardware descriptor.
- * Note that before calling this function the skb->cb array must be untouched
- * by rt2x00lib. Only after this function completes will it be save to
- * overwrite the skb->cb information.
- * The reason for this is that mac80211 writes its own tx information into
- * the skb->cb array, and this function will use that information to initialize
- * the &struct txentry_desc structure.
- */
-void rt2x00queue_create_tx_descriptor(struct queue_entry *entry,
-				      struct txentry_desc *txdesc);
-
-/**
- * rt2x00queue_write_tx_descriptor - Write TX descriptor to hardware
- * @entry: The entry which will be used to transfer the TX frame.
- * @txdesc: TX descriptor which will be used to write hardware descriptor
- *
- * This function will write a TX descriptor initialized by
- * &rt2x00queue_create_tx_descriptor to the hardware. After this call
- * has completed the frame is now owned by the hardware, the hardware
- * queue will have automatically be kicked unless this frame was generated
- * by rt2x00lib, in which case the frame is "special" and must be kicked
- * by the caller.
- */
-void rt2x00queue_write_tx_descriptor(struct queue_entry *entry,
-				     struct txentry_desc *txdesc);
-
-/**
  * rt2x00queue_get_queue - Convert queue index to queue pointer
  * @rt2x00dev: Pointer to &struct rt2x00_dev.
  * @queue: rt2x00 queue index (see &enum data_queue_qid).
diff --git a/drivers/net/wireless/rt2x00/rt2x00config.c b/drivers/net/wireless/rt2x00/rt2x00config.c
index 48608e8cc8b4..f20ca712504f 100644
--- a/drivers/net/wireless/rt2x00/rt2x00config.c
+++ b/drivers/net/wireless/rt2x00/rt2x00config.c
@@ -84,6 +84,8 @@ void rt2x00lib_config_erp(struct rt2x00_dev *rt2x00dev,
 	memset(&erp, 0, sizeof(erp));
 
 	erp.short_preamble = bss_conf->use_short_preamble;
+	erp.cts_protection = bss_conf->use_cts_prot;
+
 	erp.ack_timeout = PLCP + get_duration(ACK_SIZE, 10);
 	erp.ack_consume_time = SIFS + PLCP + get_duration(ACK_SIZE, 10);
 
diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c
index b48c04e80a38..8c93eb8353b0 100644
--- a/drivers/net/wireless/rt2x00/rt2x00dev.c
+++ b/drivers/net/wireless/rt2x00/rt2x00dev.c
@@ -409,7 +409,6 @@ static void rt2x00lib_intf_scheduled_iter(void *data, u8 *mac,
 {
 	struct rt2x00_dev *rt2x00dev = data;
 	struct rt2x00_intf *intf = vif_to_intf(vif);
-	struct sk_buff *skb;
 	struct ieee80211_bss_conf conf;
 	int delayed_flags;
 
@@ -435,12 +434,8 @@ static void rt2x00lib_intf_scheduled_iter(void *data, u8 *mac,
 	if (!test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags))
 		return;
 
-	if (delayed_flags & DELAYED_UPDATE_BEACON) {
-		skb = ieee80211_beacon_get(rt2x00dev->hw, vif);
-		if (skb &&
-		    rt2x00dev->ops->hw->beacon_update(rt2x00dev->hw, skb))
-			dev_kfree_skb(skb);
-	}
+	if (delayed_flags & DELAYED_UPDATE_BEACON)
+		rt2x00queue_update_beacon(rt2x00dev, vif);
 
 	if (delayed_flags & DELAYED_CONFIG_ERP)
 		rt2x00lib_config_erp(rt2x00dev, intf, &conf);
diff --git a/drivers/net/wireless/rt2x00/rt2x00firmware.c b/drivers/net/wireless/rt2x00/rt2x00firmware.c
index b971bc6e7ee2..bab05a56e7a0 100644
--- a/drivers/net/wireless/rt2x00/rt2x00firmware.c
+++ b/drivers/net/wireless/rt2x00/rt2x00firmware.c
@@ -100,6 +100,14 @@ int rt2x00lib_load_firmware(struct rt2x00_dev *rt2x00dev)
 	retval = rt2x00dev->ops->lib->load_firmware(rt2x00dev,
 						    rt2x00dev->fw->data,
 						    rt2x00dev->fw->size);
+
+	/*
+	 * When the firmware is uploaded to the hardware the LED
+	 * association status might have been triggered, for correct
+	 * LED handling it should now be reset.
+	 */
+	rt2x00leds_led_assoc(rt2x00dev, false);
+
 	return retval;
 }
 
diff --git a/drivers/net/wireless/rt2x00/rt2x00lib.h b/drivers/net/wireless/rt2x00/rt2x00lib.h
index eae5ce1d4de3..f2c9b0e79b5f 100644
--- a/drivers/net/wireless/rt2x00/rt2x00lib.h
+++ b/drivers/net/wireless/rt2x00/rt2x00lib.h
@@ -139,6 +139,14 @@ void rt2x00queue_free_skb(struct rt2x00_dev *rt2x00dev, struct sk_buff *skb);
 int rt2x00queue_write_tx_frame(struct data_queue *queue, struct sk_buff *skb);
 
 /**
+ * rt2x00queue_update_beacon - Send new beacon from mac80211 to hardware
+ * @rt2x00dev: Pointer to &struct rt2x00_dev.
+ * @vif: Interface for which the beacon should be updated.
+ */
+int rt2x00queue_update_beacon(struct rt2x00_dev *rt2x00dev,
+			      struct ieee80211_vif *vif);
+
+/**
  * rt2x00queue_index_inc - Index incrementation function
  * @queue: Queue (&struct data_queue) to perform the action on.
  * @index: Index type (&enum queue_index) to perform the action on.
diff --git a/drivers/net/wireless/rt2x00/rt2x00mac.c b/drivers/net/wireless/rt2x00/rt2x00mac.c
index 3a1fb6d47e5d..77af1df5d899 100644
--- a/drivers/net/wireless/rt2x00/rt2x00mac.c
+++ b/drivers/net/wireless/rt2x00/rt2x00mac.c
@@ -96,6 +96,7 @@ int rt2x00mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
 	struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
 	struct ieee80211_hdr *ieee80211hdr = (struct ieee80211_hdr *)skb->data;
 	enum data_queue_qid qid = skb_get_queue_mapping(skb);
+	struct rt2x00_intf *intf = vif_to_intf(tx_info->control.vif);
 	struct data_queue *queue;
 	u16 frame_control;
 
@@ -151,6 +152,18 @@ int rt2x00mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
 		}
 	}
 
+	/*
+	 * XXX: This is as wrong as the old mac80211 code was,
+	 *	due to beacons not getting sequence numbers assigned
+	 *	properly.
+	 */
+	if (tx_info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) {
+		if (tx_info->flags & IEEE80211_TX_CTL_FIRST_FRAGMENT)
+			intf->seqno += 0x10;
+		ieee80211hdr->seq_ctrl &= cpu_to_le16(IEEE80211_SCTL_FRAG);
+		ieee80211hdr->seq_ctrl |= cpu_to_le16(intf->seqno);
+	}
+
 	if (rt2x00queue_write_tx_frame(queue, skb)) {
 		ieee80211_stop_queue(rt2x00dev->hw, qid);
 		return NETDEV_TX_BUSY;
@@ -348,7 +361,8 @@ int rt2x00mac_config_interface(struct ieee80211_hw *hw,
 {
 	struct rt2x00_dev *rt2x00dev = hw->priv;
 	struct rt2x00_intf *intf = vif_to_intf(vif);
-	int status;
+	int update_bssid = 0;
+	int status = 0;
 
 	/*
 	 * Mac80211 might be calling this function while we are trying
@@ -360,12 +374,13 @@ int rt2x00mac_config_interface(struct ieee80211_hw *hw,
 	spin_lock(&intf->lock);
 
 	/*
-	 * If the interface does not work in master mode,
-	 * then the bssid value in the interface structure
-	 * should now be set.
+	 * conf->bssid can be NULL if coming from the internal
+	 * beacon update routine.
 	 */
-	if (conf->type != IEEE80211_IF_TYPE_AP)
+	if (conf->changed & IEEE80211_IFCC_BSSID && conf->bssid) {
+		update_bssid = 1;
 		memcpy(&intf->bssid, conf->bssid, ETH_ALEN);
+	}
 
 	spin_unlock(&intf->lock);
 
@@ -375,17 +390,14 @@ int rt2x00mac_config_interface(struct ieee80211_hw *hw,
 	 * values as arguments we make keep access to rt2x00_intf thread safe
 	 * even without the lock.
 	 */
-	rt2x00lib_config_intf(rt2x00dev, intf, conf->type, NULL, conf->bssid);
+	rt2x00lib_config_intf(rt2x00dev, intf, vif->type, NULL,
+			      update_bssid ? conf->bssid : NULL);
 
 	/*
-	 * We only need to initialize the beacon when master mode is enabled.
+	 * Update the beacon.
 	 */
-	if (conf->type != IEEE80211_IF_TYPE_AP || !conf->beacon)
-		return 0;
-
-	status = rt2x00dev->ops->hw->beacon_update(rt2x00dev->hw, conf->beacon);
-	if (status)
-		dev_kfree_skb(conf->beacon);
+	if (conf->changed & IEEE80211_IFCC_BEACON)
+		status = rt2x00queue_update_beacon(rt2x00dev, vif);
 
 	return status;
 }
@@ -501,7 +513,7 @@ void rt2x00mac_bss_info_changed(struct ieee80211_hw *hw,
 	 * When the erp information has changed, we should perform
 	 * additional configuration steps. For all other changes we are done.
 	 */
-	if (changes & BSS_CHANGED_ERP_PREAMBLE) {
+	if (changes & (BSS_CHANGED_ERP_PREAMBLE | BSS_CHANGED_ERP_CTS_PROT)) {
 		if (!test_bit(DRIVER_REQUIRE_SCHEDULED, &rt2x00dev->flags))
 			rt2x00lib_config_erp(rt2x00dev, intf, bss_conf);
 		else
diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.c b/drivers/net/wireless/rt2x00/rt2x00queue.c
index 3ddce538ef4a..7f442030f5ad 100644
--- a/drivers/net/wireless/rt2x00/rt2x00queue.c
+++ b/drivers/net/wireless/rt2x00/rt2x00queue.c
@@ -108,12 +108,15 @@ void rt2x00queue_unmap_skb(struct rt2x00_dev *rt2x00dev, struct sk_buff *skb)
 
 void rt2x00queue_free_skb(struct rt2x00_dev *rt2x00dev, struct sk_buff *skb)
 {
+	if (!skb)
+		return;
+
 	rt2x00queue_unmap_skb(rt2x00dev, skb);
 	dev_kfree_skb_any(skb);
 }
 
-void rt2x00queue_create_tx_descriptor(struct queue_entry *entry,
-				      struct txentry_desc *txdesc)
+static void rt2x00queue_create_tx_descriptor(struct queue_entry *entry,
+					     struct txentry_desc *txdesc)
 {
 	struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
 	struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(entry->skb);
@@ -237,10 +240,9 @@ void rt2x00queue_create_tx_descriptor(struct queue_entry *entry,
 			txdesc->signal |= 0x08;
 	}
 }
-EXPORT_SYMBOL_GPL(rt2x00queue_create_tx_descriptor);
 
-void rt2x00queue_write_tx_descriptor(struct queue_entry *entry,
-				     struct txentry_desc *txdesc)
+static void rt2x00queue_write_tx_descriptor(struct queue_entry *entry,
+					    struct txentry_desc *txdesc)
 {
 	struct data_queue *queue = entry->queue;
 	struct rt2x00_dev *rt2x00dev = queue->rt2x00dev;
@@ -270,7 +272,6 @@ void rt2x00queue_write_tx_descriptor(struct queue_entry *entry,
 	    !test_bit(ENTRY_TXD_BURST, &txdesc->flags))
 		rt2x00dev->ops->lib->kick_tx_queue(rt2x00dev, queue->qid);
 }
-EXPORT_SYMBOL_GPL(rt2x00queue_write_tx_descriptor);
 
 int rt2x00queue_write_tx_frame(struct data_queue *queue, struct sk_buff *skb)
 {
@@ -320,6 +321,60 @@ int rt2x00queue_write_tx_frame(struct data_queue *queue, struct sk_buff *skb)
 	return 0;
 }
 
+int rt2x00queue_update_beacon(struct rt2x00_dev *rt2x00dev,
+			      struct ieee80211_vif *vif)
+{
+	struct rt2x00_intf *intf = vif_to_intf(vif);
+	struct skb_frame_desc *skbdesc;
+	struct txentry_desc txdesc;
+	__le32 desc[16];
+
+	if (unlikely(!intf->beacon))
+		return -ENOBUFS;
+
+	intf->beacon->skb = ieee80211_beacon_get(rt2x00dev->hw, vif);
+	if (!intf->beacon->skb)
+		return -ENOMEM;
+
+	/*
+	 * Copy all TX descriptor information into txdesc,
+	 * after that we are free to use the skb->cb array
+	 * for our information.
+	 */
+	rt2x00queue_create_tx_descriptor(intf->beacon, &txdesc);
+
+	/*
+	 * For the descriptor we use a local array from where the
+	 * driver can move it to the correct location required for
+	 * the hardware.
+	 */
+	memset(desc, 0, sizeof(desc));
+
+	/*
+	 * Fill in skb descriptor
+	 */
+	skbdesc = get_skb_frame_desc(intf->beacon->skb);
+	memset(skbdesc, 0, sizeof(*skbdesc));
+	skbdesc->desc = desc;
+	skbdesc->desc_len = intf->beacon->queue->desc_size;
+	skbdesc->entry = intf->beacon;
+
+	/*
+	 * Write TX descriptor into reserved room in front of the beacon.
+	 */
+	rt2x00queue_write_tx_descriptor(intf->beacon, &txdesc);
+
+	/*
+	 * Send beacon to hardware.
+	 * Also enable beacon generation, which might have been disabled
+	 * by the driver during the config_beacon() callback function.
+	 */
+	rt2x00dev->ops->lib->write_beacon(intf->beacon);
+	rt2x00dev->ops->lib->kick_tx_queue(rt2x00dev, QID_BEACON);
+
+	return 0;
+}
+
 struct data_queue *rt2x00queue_get_queue(struct rt2x00_dev *rt2x00dev,
 					 const enum data_queue_qid queue)
 {
diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c
index 5a1330c5de71..70ef7bf434ab 100644
--- a/drivers/net/wireless/rt2x00/rt61pci.c
+++ b/drivers/net/wireless/rt2x00/rt61pci.c
@@ -1600,6 +1600,41 @@ static void rt61pci_write_tx_desc(struct rt2x00_dev *rt2x00dev,
 /*
  * TX data initialization
  */
+static void rt61pci_write_beacon(struct queue_entry *entry)
+{
+	struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
+	struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb);
+	unsigned int beacon_base;
+	u32 reg;
+
+	/*
+	 * Disable beaconing while we are reloading the beacon data,
+	 * otherwise we might be sending out invalid data.
+	 */
+	rt2x00pci_register_read(rt2x00dev, TXRX_CSR9, &reg);
+	rt2x00_set_field32(&reg, TXRX_CSR9_TSF_TICKING, 0);
+	rt2x00_set_field32(&reg, TXRX_CSR9_TBTT_ENABLE, 0);
+	rt2x00_set_field32(&reg, TXRX_CSR9_BEACON_GEN, 0);
+	rt2x00pci_register_write(rt2x00dev, TXRX_CSR9, reg);
+
+	/*
+	 * Write entire beacon with descriptor to register.
+	 */
+	beacon_base = HW_BEACON_OFFSET(entry->entry_idx);
+	rt2x00pci_register_multiwrite(rt2x00dev,
+				      beacon_base,
+				      skbdesc->desc, skbdesc->desc_len);
+	rt2x00pci_register_multiwrite(rt2x00dev,
+				      beacon_base + skbdesc->desc_len,
+				      entry->skb->data, entry->skb->len);
+
+	/*
+	 * Clean up beacon skb.
+	 */
+	dev_kfree_skb_any(entry->skb);
+	entry->skb = NULL;
+}
+
 static void rt61pci_kick_tx_queue(struct rt2x00_dev *rt2x00dev,
 				  const enum data_queue_qid queue)
 {
@@ -2355,72 +2390,6 @@ static u64 rt61pci_get_tsf(struct ieee80211_hw *hw)
 	return tsf;
 }
 
-static int rt61pci_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb)
-{
-	struct rt2x00_dev *rt2x00dev = hw->priv;
-	struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
-	struct rt2x00_intf *intf = vif_to_intf(tx_info->control.vif);
-	struct queue_entry_priv_pci *entry_priv;
-	struct skb_frame_desc *skbdesc;
-	struct txentry_desc txdesc;
-	unsigned int beacon_base;
-	u32 reg;
-
-	if (unlikely(!intf->beacon))
-		return -ENOBUFS;
-
-	/*
-	 * Copy all TX descriptor information into txdesc,
-	 * after that we are free to use the skb->cb array
-	 * for our information.
-	 */
-	intf->beacon->skb = skb;
-	rt2x00queue_create_tx_descriptor(intf->beacon, &txdesc);
-
-	entry_priv = intf->beacon->priv_data;
-	memset(entry_priv->desc, 0, intf->beacon->queue->desc_size);
-
-	/*
-	 * Fill in skb descriptor
-	 */
-	skbdesc = get_skb_frame_desc(skb);
-	memset(skbdesc, 0, sizeof(*skbdesc));
-	skbdesc->desc = entry_priv->desc;
-	skbdesc->desc_len = intf->beacon->queue->desc_size;
-	skbdesc->entry = intf->beacon;
-
-	/*
-	 * Disable beaconing while we are reloading the beacon data,
-	 * otherwise we might be sending out invalid data.
-	 */
-	rt2x00pci_register_read(rt2x00dev, TXRX_CSR9, &reg);
-	rt2x00_set_field32(&reg, TXRX_CSR9_TSF_TICKING, 0);
-	rt2x00_set_field32(&reg, TXRX_CSR9_TBTT_ENABLE, 0);
-	rt2x00_set_field32(&reg, TXRX_CSR9_BEACON_GEN, 0);
-	rt2x00pci_register_write(rt2x00dev, TXRX_CSR9, reg);
-
-	/*
-	 * Write entire beacon with descriptor to register,
-	 * and kick the beacon generator.
-	 */
-	rt2x00queue_write_tx_descriptor(intf->beacon, &txdesc);
-	beacon_base = HW_BEACON_OFFSET(intf->beacon->entry_idx);
-	rt2x00pci_register_multiwrite(rt2x00dev, beacon_base,
-				      skbdesc->desc, skbdesc->desc_len);
-	rt2x00pci_register_multiwrite(rt2x00dev,
-				      beacon_base + skbdesc->desc_len,
-				      skb->data, skb->len);
-	rt61pci_kick_tx_queue(rt2x00dev, QID_BEACON);
-
-	/*
-	 * Clean up beacon skb.
-	 */
-	dev_kfree_skb_any(skb);
-	intf->beacon->skb = NULL;
-
-	return 0;
-}
-
 static const struct ieee80211_ops rt61pci_mac80211_ops = {
 	.tx			= rt2x00mac_tx,
 	.start			= rt2x00mac_start,
@@ -2436,7 +2405,6 @@ static const struct ieee80211_ops rt61pci_mac80211_ops = {
 	.conf_tx		= rt2x00mac_conf_tx,
 	.get_tx_stats		= rt2x00mac_get_tx_stats,
 	.get_tsf		= rt61pci_get_tsf,
-	.beacon_update		= rt61pci_beacon_update,
 };
 
 static const struct rt2x00lib_ops rt61pci_rt2x00_ops = {
@@ -2456,6 +2424,7 @@ static const struct rt2x00lib_ops rt61pci_rt2x00_ops = {
 	.link_tuner		= rt61pci_link_tuner,
 	.write_tx_desc		= rt61pci_write_tx_desc,
 	.write_tx_data		= rt2x00pci_write_tx_data,
+	.write_beacon		= rt61pci_write_beacon,
 	.kick_tx_queue		= rt61pci_kick_tx_queue,
 	.fill_rxdone		= rt61pci_fill_rxdone,
 	.config_filter		= rt61pci_config_filter,
diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c
index 25d8b660051f..34c6ff27afc4 100644
--- a/drivers/net/wireless/rt2x00/rt73usb.c
+++ b/drivers/net/wireless/rt2x00/rt73usb.c
@@ -1343,6 +1343,49 @@ static void rt73usb_write_tx_desc(struct rt2x00_dev *rt2x00dev,
 	rt2x00_desc_write(txd, 0, word);
 }
 
+/*
+ * TX data initialization
+ */
+static void rt73usb_write_beacon(struct queue_entry *entry)
+{
+	struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
+	struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb);
+	unsigned int beacon_base;
+	u32 reg;
+
+	/*
+	 * Add the descriptor in front of the skb.
+	 */
+	skb_push(entry->skb, entry->queue->desc_size);
+	memcpy(entry->skb->data, skbdesc->desc, skbdesc->desc_len);
+	skbdesc->desc = entry->skb->data;
+
+	/*
+	 * Disable beaconing while we are reloading the beacon data,
+	 * otherwise we might be sending out invalid data.
+	 */
+	rt73usb_register_read(rt2x00dev, TXRX_CSR9, &reg);
+	rt2x00_set_field32(&reg, TXRX_CSR9_TSF_TICKING, 0);
+	rt2x00_set_field32(&reg, TXRX_CSR9_TBTT_ENABLE, 0);
+	rt2x00_set_field32(&reg, TXRX_CSR9_BEACON_GEN, 0);
+	rt73usb_register_write(rt2x00dev, TXRX_CSR9, reg);
+
+	/*
+	 * Write entire beacon with descriptor to register.
+	 */
+	beacon_base = HW_BEACON_OFFSET(entry->entry_idx);
+	rt2x00usb_vendor_request(rt2x00dev, USB_MULTI_WRITE,
+				 USB_VENDOR_REQUEST_OUT, beacon_base, 0,
+				 entry->skb->data, entry->skb->len,
+				 REGISTER_TIMEOUT32(entry->skb->len));
+
+	/*
+	 * Clean up the beacon skb.
+	 */
+	dev_kfree_skb(entry->skb);
+	entry->skb = NULL;
+}
+
 static int rt73usb_get_tx_data_len(struct rt2x00_dev *rt2x00dev,
 				   struct sk_buff *skb)
 {
@@ -1358,9 +1401,6 @@ static int rt73usb_get_tx_data_len(struct rt2x00_dev *rt2x00dev,
 	return length;
 }
 
-/*
- * TX data initialization
- */
 static void rt73usb_kick_tx_queue(struct rt2x00_dev *rt2x00dev,
 				  const enum data_queue_qid queue)
 {
@@ -1958,73 +1998,6 @@ static u64 rt73usb_get_tsf(struct ieee80211_hw *hw)
 #define rt73usb_get_tsf	NULL
 #endif
 
-static int rt73usb_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb)
-{
-	struct rt2x00_dev *rt2x00dev = hw->priv;
-	struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
-	struct rt2x00_intf *intf = vif_to_intf(tx_info->control.vif);
-	struct skb_frame_desc *skbdesc;
-	struct txentry_desc txdesc;
-	unsigned int beacon_base;
-	u32 reg;
-
-	if (unlikely(!intf->beacon))
-		return -ENOBUFS;
-
-	/*
-	 * Copy all TX descriptor information into txdesc,
-	 * after that we are free to use the skb->cb array
-	 * for our information.
-	 */
-	intf->beacon->skb = skb;
-	rt2x00queue_create_tx_descriptor(intf->beacon, &txdesc);
-
-	/*
-	 * Add the descriptor in front of the skb.
-	 */
-	skb_push(skb, intf->beacon->queue->desc_size);
-	memset(skb->data, 0, intf->beacon->queue->desc_size);
-
-	/*
-	 * Fill in skb descriptor
-	 */
-	skbdesc = get_skb_frame_desc(skb);
-	memset(skbdesc, 0, sizeof(*skbdesc));
-	skbdesc->desc = skb->data;
-	skbdesc->desc_len = intf->beacon->queue->desc_size;
-	skbdesc->entry = intf->beacon;
-
-	/*
-	 * Disable beaconing while we are reloading the beacon data,
-	 * otherwise we might be sending out invalid data.
-	 */
-	rt73usb_register_read(rt2x00dev, TXRX_CSR9, &reg);
-	rt2x00_set_field32(&reg, TXRX_CSR9_TSF_TICKING, 0);
-	rt2x00_set_field32(&reg, TXRX_CSR9_TBTT_ENABLE, 0);
-	rt2x00_set_field32(&reg, TXRX_CSR9_BEACON_GEN, 0);
-	rt73usb_register_write(rt2x00dev, TXRX_CSR9, reg);
-
-	/*
-	 * Write entire beacon with descriptor to register,
-	 * and kick the beacon generator.
-	 */
-	rt2x00queue_write_tx_descriptor(intf->beacon, &txdesc);
-	beacon_base = HW_BEACON_OFFSET(intf->beacon->entry_idx);
-	rt2x00usb_vendor_request(rt2x00dev, USB_MULTI_WRITE,
-				 USB_VENDOR_REQUEST_OUT, beacon_base, 0,
-				 skb->data, skb->len,
-				 REGISTER_TIMEOUT32(skb->len));
-	rt73usb_kick_tx_queue(rt2x00dev, QID_BEACON);
-
-	/*
-	 * Clean up the beacon skb.
-	 */
-	dev_kfree_skb(skb);
-	intf->beacon->skb = NULL;
-
-	return 0;
-}
-
 static const struct ieee80211_ops rt73usb_mac80211_ops = {
 	.tx			= rt2x00mac_tx,
 	.start			= rt2x00mac_start,
@@ -2040,7 +2013,6 @@ static const struct ieee80211_ops rt73usb_mac80211_ops = {
 	.conf_tx		= rt2x00mac_conf_tx,
 	.get_tx_stats		= rt2x00mac_get_tx_stats,
 	.get_tsf		= rt73usb_get_tsf,
-	.beacon_update		= rt73usb_beacon_update,
 };
 
 static const struct rt2x00lib_ops rt73usb_rt2x00_ops = {
@@ -2058,6 +2030,7 @@ static const struct rt2x00lib_ops rt73usb_rt2x00_ops = {
 	.link_tuner		= rt73usb_link_tuner,
 	.write_tx_desc		= rt73usb_write_tx_desc,
 	.write_tx_data		= rt2x00usb_write_tx_data,
+	.write_beacon		= rt73usb_write_beacon,
 	.get_tx_data_len	= rt73usb_get_tx_data_len,
 	.kick_tx_queue		= rt73usb_kick_tx_queue,
 	.fill_rxdone		= rt73usb_fill_rxdone,
diff --git a/drivers/net/wireless/rtl8187_dev.c b/drivers/net/wireless/rtl8187_dev.c
index 33527e58256f..d3067b1216ca 100644
--- a/drivers/net/wireless/rtl8187_dev.c
+++ b/drivers/net/wireless/rtl8187_dev.c
@@ -430,8 +430,10 @@ static int rtl8187_init_hw(struct ieee80211_hw *dev)
 	reg = rtl818x_ioread8(priv, &priv->map->CONFIG3);
 	rtl818x_iowrite8(priv, &priv->map->CONFIG3, reg |
 			 RTL818X_CONFIG3_ANAPARAM_WRITE);
-	rtl818x_iowrite32(priv, &priv->map->ANAPARAM, RTL8225_ANAPARAM_ON);
-	rtl818x_iowrite32(priv, &priv->map->ANAPARAM2, RTL8225_ANAPARAM2_ON);
+	rtl818x_iowrite32(priv, &priv->map->ANAPARAM,
+			  RTL8187_RTL8225_ANAPARAM_ON);
+	rtl818x_iowrite32(priv, &priv->map->ANAPARAM2,
+			  RTL8187_RTL8225_ANAPARAM2_ON);
 	rtl818x_iowrite8(priv, &priv->map->CONFIG3, reg &
 			 ~RTL818X_CONFIG3_ANAPARAM_WRITE);
 	rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD,
@@ -453,8 +455,10 @@ static int rtl8187_init_hw(struct ieee80211_hw *dev)
 	reg = rtl818x_ioread8(priv, &priv->map->CONFIG3);
 	rtl818x_iowrite8(priv, &priv->map->CONFIG3,
 			reg | RTL818X_CONFIG3_ANAPARAM_WRITE);
-	rtl818x_iowrite32(priv, &priv->map->ANAPARAM, RTL8225_ANAPARAM_ON);
-	rtl818x_iowrite32(priv, &priv->map->ANAPARAM2, RTL8225_ANAPARAM2_ON);
+	rtl818x_iowrite32(priv, &priv->map->ANAPARAM,
+			  RTL8187_RTL8225_ANAPARAM_ON);
+	rtl818x_iowrite32(priv, &priv->map->ANAPARAM2,
+			  RTL8187_RTL8225_ANAPARAM2_ON);
 	rtl818x_iowrite8(priv, &priv->map->CONFIG3,
 			reg & ~RTL818X_CONFIG3_ANAPARAM_WRITE);
 	rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL);
@@ -566,9 +570,12 @@ static int rtl8187b_init_hw(struct ieee80211_hw *dev)
 	reg = rtl818x_ioread8(priv, &priv->map->CONFIG3);
 	reg |= RTL818X_CONFIG3_ANAPARAM_WRITE | RTL818X_CONFIG3_GNT_SELECT;
 	rtl818x_iowrite8(priv, &priv->map->CONFIG3, reg);
-	rtl818x_iowrite32(priv, &priv->map->ANAPARAM2, 0x727f3f52);
-	rtl818x_iowrite32(priv, &priv->map->ANAPARAM, 0x45090658);
-	rtl818x_iowrite8(priv, &priv->map->ANAPARAM3, 0);
+	rtl818x_iowrite32(priv, &priv->map->ANAPARAM2,
+			  RTL8187B_RTL8225_ANAPARAM2_ON);
+	rtl818x_iowrite32(priv, &priv->map->ANAPARAM,
+			  RTL8187B_RTL8225_ANAPARAM_ON);
+	rtl818x_iowrite8(priv, &priv->map->ANAPARAM3,
+			 RTL8187B_RTL8225_ANAPARAM3_ON);
 
 	rtl818x_iowrite8(priv, (u8 *)0xFF61, 0x10);
 	reg = rtl818x_ioread8(priv, (u8 *)0xFF62);
@@ -1180,7 +1187,7 @@ static struct usb_driver rtl8187_driver = {
 	.name		= KBUILD_MODNAME,
 	.id_table	= rtl8187_table,
 	.probe		= rtl8187_probe,
-	.disconnect	= rtl8187_disconnect,
+	.disconnect	= __devexit_p(rtl8187_disconnect),
 };
 
 static int __init rtl8187_init(void)
diff --git a/drivers/net/wireless/rtl8187_rtl8225.c b/drivers/net/wireless/rtl8187_rtl8225.c
index 1e059de97116..1bae89903410 100644
--- a/drivers/net/wireless/rtl8187_rtl8225.c
+++ b/drivers/net/wireless/rtl8187_rtl8225.c
@@ -307,7 +307,8 @@ static void rtl8225_rf_set_tx_power(struct ieee80211_hw *dev, int channel)
 	reg = rtl818x_ioread8(priv, &priv->map->CONFIG3);
 	rtl818x_iowrite8(priv, &priv->map->CONFIG3,
 			reg | RTL818X_CONFIG3_ANAPARAM_WRITE);
-	rtl818x_iowrite32(priv, &priv->map->ANAPARAM2, RTL8225_ANAPARAM2_ON);
+	rtl818x_iowrite32(priv, &priv->map->ANAPARAM2,
+			  RTL8187_RTL8225_ANAPARAM2_ON);
 	rtl818x_iowrite8(priv, &priv->map->CONFIG3,
 			reg & ~RTL818X_CONFIG3_ANAPARAM_WRITE);
 	rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL);
@@ -560,7 +561,8 @@ static void rtl8225z2_rf_set_tx_power(struct ieee80211_hw *dev, int channel)
 	reg = rtl818x_ioread8(priv, &priv->map->CONFIG3);
 	rtl818x_iowrite8(priv, &priv->map->CONFIG3,
 			reg | RTL818X_CONFIG3_ANAPARAM_WRITE);
-	rtl818x_iowrite32(priv, &priv->map->ANAPARAM2, RTL8225_ANAPARAM2_ON);
+	rtl818x_iowrite32(priv, &priv->map->ANAPARAM2,
+			  RTL8187_RTL8225_ANAPARAM2_ON);
 	rtl818x_iowrite8(priv, &priv->map->CONFIG3,
 			reg & ~RTL818X_CONFIG3_ANAPARAM_WRITE);
 	rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL);
@@ -913,8 +915,19 @@ static void rtl8225_rf_stop(struct ieee80211_hw *dev)
 	rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG);
 	reg = rtl818x_ioread8(priv, &priv->map->CONFIG3);
 	rtl818x_iowrite8(priv, &priv->map->CONFIG3, reg | RTL818X_CONFIG3_ANAPARAM_WRITE);
-	rtl818x_iowrite32(priv, &priv->map->ANAPARAM2, RTL8225_ANAPARAM2_OFF);
-	rtl818x_iowrite32(priv, &priv->map->ANAPARAM, RTL8225_ANAPARAM_OFF);
+	if (!priv->is_rtl8187b) {
+		rtl818x_iowrite32(priv, &priv->map->ANAPARAM2,
+				  RTL8187_RTL8225_ANAPARAM2_OFF);
+		rtl818x_iowrite32(priv, &priv->map->ANAPARAM,
+				  RTL8187_RTL8225_ANAPARAM_OFF);
+	} else {
+		rtl818x_iowrite32(priv, &priv->map->ANAPARAM2,
+				  RTL8187B_RTL8225_ANAPARAM2_OFF);
+		rtl818x_iowrite32(priv, &priv->map->ANAPARAM,
+				  RTL8187B_RTL8225_ANAPARAM_OFF);
+		rtl818x_iowrite8(priv, &priv->map->ANAPARAM3,
+				  RTL8187B_RTL8225_ANAPARAM3_OFF);
+	}
 	rtl818x_iowrite8(priv, &priv->map->CONFIG3, reg & ~RTL818X_CONFIG3_ANAPARAM_WRITE);
 	rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL);
 }
diff --git a/drivers/net/wireless/rtl8187_rtl8225.h b/drivers/net/wireless/rtl8187_rtl8225.h
index d39ed0295b6e..20c5b6ead0f6 100644
--- a/drivers/net/wireless/rtl8187_rtl8225.h
+++ b/drivers/net/wireless/rtl8187_rtl8225.h
@@ -15,10 +15,17 @@
 #ifndef RTL8187_RTL8225_H
 #define RTL8187_RTL8225_H
 
-#define RTL8225_ANAPARAM_ON	0xa0000a59
-#define RTL8225_ANAPARAM2_ON	0x860c7312
-#define RTL8225_ANAPARAM_OFF	0xa00beb59
-#define RTL8225_ANAPARAM2_OFF	0x840dec11
+#define RTL8187_RTL8225_ANAPARAM_ON	0xa0000a59
+#define RTL8187_RTL8225_ANAPARAM2_ON	0x860c7312
+#define RTL8187_RTL8225_ANAPARAM_OFF	0xa00beb59
+#define RTL8187_RTL8225_ANAPARAM2_OFF	0x840dec11
+
+#define RTL8187B_RTL8225_ANAPARAM_ON	0x45090658
+#define RTL8187B_RTL8225_ANAPARAM2_ON	0x727f3f52
+#define RTL8187B_RTL8225_ANAPARAM3_ON	0x00
+#define RTL8187B_RTL8225_ANAPARAM_OFF	0x55480658
+#define RTL8187B_RTL8225_ANAPARAM2_OFF	0x72003f50
+#define RTL8187B_RTL8225_ANAPARAM3_OFF	0x00
 
 const struct rtl818x_rf_ops * rtl8187_detect_rf(struct ieee80211_hw *);
 
diff --git a/drivers/net/wireless/zd1211rw/zd_mac.c b/drivers/net/wireless/zd1211rw/zd_mac.c
index feaf43d17249..fcc532bb6a7e 100644
--- a/drivers/net/wireless/zd1211rw/zd_mac.c
+++ b/drivers/net/wireless/zd1211rw/zd_mac.c
@@ -728,15 +728,19 @@ static int zd_op_config_interface(struct ieee80211_hw *hw,
 	if (mac->type == IEEE80211_IF_TYPE_MESH_POINT ||
 	    mac->type == IEEE80211_IF_TYPE_IBSS) {
 		associated = true;
-		if (conf->beacon) {
-			r = zd_mac_config_beacon(hw, conf->beacon);
+		if (conf->changed & IEEE80211_IFCC_BEACON) {
+			struct sk_buff *beacon = ieee80211_beacon_get(hw, vif);
+
+			if (!beacon)
+				return -ENOMEM;
+			r = zd_mac_config_beacon(hw, beacon);
 			if (r < 0)
 				return r;
 			r = zd_set_beacon_interval(&mac->chip, BCN_MODE_IBSS |
 					hw->conf.beacon_int);
 			if (r < 0)
 				return r;
-			kfree_skb(conf->beacon);
+			kfree_skb(beacon);
 		}
 	} else
 		associated = is_valid_ether_addr(conf->bssid);
@@ -890,17 +894,6 @@ static void zd_op_bss_info_changed(struct ieee80211_hw *hw,
 	}
 }
 
-static int zd_op_beacon_update(struct ieee80211_hw *hw,
-			       struct sk_buff *skb)
-{
-	struct zd_mac *mac = zd_hw_mac(hw);
-	zd_mac_config_beacon(hw, skb);
-	kfree_skb(skb);
-	zd_set_beacon_interval(&mac->chip, BCN_MODE_IBSS |
-					hw->conf.beacon_int);
-	return 0;
-}
-
 static const struct ieee80211_ops zd_ops = {
 	.tx			= zd_op_tx,
 	.start			= zd_op_start,
@@ -911,7 +904,6 @@ static const struct ieee80211_ops zd_ops = {
 	.config_interface	= zd_op_config_interface,
 	.configure_filter	= zd_op_configure_filter,
 	.bss_info_changed	= zd_op_bss_info_changed,
-	.beacon_update		= zd_op_beacon_update,
 };
 
 struct ieee80211_hw *zd_mac_alloc_hw(struct usb_interface *intf)
diff --git a/include/linux/ssb/ssb.h b/include/linux/ssb/ssb.h
index 0fe5a0ded3ea..4bf8cade9dbc 100644
--- a/include/linux/ssb/ssb.h
+++ b/include/linux/ssb/ssb.h
@@ -7,6 +7,7 @@
 #include <linux/spinlock.h>
 #include <linux/pci.h>
 #include <linux/mod_devicetable.h>
+#include <linux/dma-mapping.h>
 
 #include <linux/ssb/ssb_regs.h>
 
diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index 656442c6b1c3..24a69f6075c2 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -115,17 +115,17 @@ enum ieee80211_max_queues {
  * The information provided in this structure is required for QoS
  * transmit queue configuration. Cf. IEEE 802.11 7.3.2.29.
  *
- * @aifs: arbitration interface space [0..255, -1: use default]
- * @cw_min: minimum contention window [will be a value of the form
- *	2^n-1 in the range 1..1023; 0: use default]
+ * @aifs: arbitration interface space [0..255]
+ * @cw_min: minimum contention window [a value of the form
+ *	2^n-1 in the range 1..32767]
  * @cw_max: maximum contention window [like @cw_min]
  * @txop: maximum burst time in units of 32 usecs, 0 meaning disabled
  */
 struct ieee80211_tx_queue_params {
-	s16 aifs;
+	u16 txop;
 	u16 cw_min;
 	u16 cw_max;
-	u16 txop;
+	u8 aifs;
 };
 
 /**
@@ -239,6 +239,17 @@ struct ieee80211_bss_conf {
  * 	is for the whole aggregation.
  * @IEEE80211_TX_STAT_AMPDU_NO_BACK: no block ack was returned,
  * 	so consider using block ack request (BAR).
+ * @IEEE80211_TX_CTL_ASSIGN_SEQ: The driver has to assign a sequence
+ *	number to this frame, taking care of not overwriting the fragment
+ *	number and increasing the sequence number only when the
+ *	IEEE80211_TX_CTL_FIRST_FRAGMENT flags is set. mac80211 will properly
+ *	assign sequence numbers to QoS-data frames but cannot do so correctly
+ *	for non-QoS-data and management frames because beacons need them from
+ *	that counter as well and mac80211 cannot guarantee proper sequencing.
+ *	If this flag is set, the driver should instruct the hardware to
+ *	assign a sequence number to the frame or assign one itself. Cf. IEEE
+ *	802.11-2007 7.1.3.4.1 paragraph 3. This flag will always be set for
+ *	beacons always be clear for frames without a sequence number field.
  */
 enum mac80211_tx_control_flags {
 	IEEE80211_TX_CTL_REQ_TX_STATUS		= BIT(0),
@@ -265,6 +276,7 @@ enum mac80211_tx_control_flags {
 	IEEE80211_TX_STAT_ACK			= BIT(21),
 	IEEE80211_TX_STAT_AMPDU			= BIT(22),
 	IEEE80211_TX_STAT_AMPDU_NO_BACK		= BIT(23),
+	IEEE80211_TX_CTL_ASSIGN_SEQ		= BIT(24),
 };
 
 
@@ -407,11 +419,13 @@ struct ieee80211_rx_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)
+ * @IEEE80211_CONF_PS: Enable 802.11 power save mode
  */
 enum ieee80211_conf_flags {
 	IEEE80211_CONF_SHORT_SLOT_TIME	= (1<<0),
 	IEEE80211_CONF_RADIOTAP		= (1<<1),
 	IEEE80211_CONF_SUPPORT_HT_MODE	= (1<<2),
+	IEEE80211_CONF_PS		= (1<<3),
 };
 
 /**
@@ -527,33 +541,38 @@ struct ieee80211_if_init_conf {
 };
 
 /**
+ * enum ieee80211_if_conf_change - interface config change flags
+ *
+ * @IEEE80211_IFCC_BSSID: The BSSID changed.
+ * @IEEE80211_IFCC_SSID: The SSID changed.
+ * @IEEE80211_IFCC_BEACON: The beacon for this interface changed
+ *	(currently AP and MESH only), use ieee80211_beacon_get().
+ */
+enum ieee80211_if_conf_change {
+	IEEE80211_IFCC_BSSID	= BIT(0),
+	IEEE80211_IFCC_SSID	= BIT(1),
+	IEEE80211_IFCC_BEACON	= BIT(2),
+};
+
+/**
  * struct ieee80211_if_conf - configuration of an interface
  *
- * @type: type of the interface. This is always the same as was specified in
- *	&struct ieee80211_if_init_conf. The type of an interface never changes
- *	during the life of the interface; this field is present only for
- *	convenience.
+ * @changed: parameters that have changed, see &enum ieee80211_if_conf_change.
  * @bssid: BSSID of the network we are associated to/creating.
  * @ssid: used (together with @ssid_len) by drivers for hardware that
  *	generate beacons independently. The pointer is valid only during the
  *	config_interface() call, so copy the value somewhere if you need
  *	it.
  * @ssid_len: length of the @ssid field.
- * @beacon: beacon template. Valid only if @host_gen_beacon_template in
- *	&struct ieee80211_hw is set. The driver is responsible of freeing
- *	the sk_buff.
- * @beacon_control: tx_control for the beacon template, this field is only
- *	valid when the @beacon field was set.
  *
  * This structure is passed to the config_interface() callback of
  * &struct ieee80211_hw.
  */
 struct ieee80211_if_conf {
-	int type;
+	u32 changed;
 	u8 *bssid;
 	u8 *ssid;
 	size_t ssid_len;
-	struct sk_buff *beacon;
 };
 
 /**
@@ -681,15 +700,6 @@ enum ieee80211_tkip_key_type {
  * any particular flags. There are some exceptions to this rule,
  * however, so you are advised to review these flags carefully.
  *
- * @IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE:
- *	The device only needs to be supplied with a beacon template.
- *	If you need the host to generate each beacon then don't use
- *	this flag and call ieee80211_beacon_get() when you need the
- *	next beacon frame. Note that if you set this flag, you must
- *	implement the set_tim() callback for powersave mode to work
- *	properly.
- *	This flag is only relevant for access-point mode.
- *
  * @IEEE80211_HW_RX_INCLUDES_FCS:
  *	Indicates that received frames passed to the stack include
  *	the FCS at the end.
@@ -1149,17 +1159,6 @@ enum ieee80211_ampdu_mlme_action {
  *	function is optional if the firmware/hardware takes full care of
  *	TSF synchronization.
  *
- * @beacon_update: Setup beacon data for IBSS beacons. Unlike access point,
- *	IBSS uses a fixed beacon frame which is configured using this
- *	function.
- *	If the driver returns success (0) from this callback, it owns
- *	the skb. That means the driver is responsible to kfree_skb() it.
- *	The control structure is not dynamically allocated. That means the
- *	driver does not own the pointer and if it needs it somewhere
- *	outside of the context of this function, it must copy it
- *	somewhere else.
- *	This handler is required only for IBSS mode.
- *
  * @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.
@@ -1217,8 +1216,6 @@ struct ieee80211_ops {
 			    struct ieee80211_tx_queue_stats *stats);
 	u64 (*get_tsf)(struct ieee80211_hw *hw);
 	void (*reset_tsf)(struct ieee80211_hw *hw);
-	int (*beacon_update)(struct ieee80211_hw *hw,
-			     struct sk_buff *skb);
 	int (*tx_last_beacon)(struct ieee80211_hw *hw);
 	int (*ampdu_action)(struct ieee80211_hw *hw,
 			    enum ieee80211_ampdu_mlme_action action,
diff --git a/net/core/net-sysfs.c b/net/core/net-sysfs.c
index 3f7941319217..c1f4e0d428c0 100644
--- a/net/core/net-sysfs.c
+++ b/net/core/net-sysfs.c
@@ -318,7 +318,7 @@ static struct attribute_group netstat_group = {
 	.attrs  = netstat_attrs,
 };
 
-#ifdef CONFIG_WIRELESS_EXT
+#ifdef CONFIG_WIRELESS_EXT_SYSFS
 /* helper function that does all the locking etc for wireless stats */
 static ssize_t wireless_show(struct device *d, char *buf,
 			     ssize_t (*format)(const struct iw_statistics *,
@@ -459,7 +459,7 @@ int netdev_register_kobject(struct net_device *net)
 #ifdef CONFIG_SYSFS
 	*groups++ = &netstat_group;
 
-#ifdef CONFIG_WIRELESS_EXT
+#ifdef CONFIG_WIRELESS_EXT_SYSFS
 	if (net->wireless_handlers && net->wireless_handlers->get_wireless_stats)
 		*groups++ = &wireless_group;
 #endif
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index 81087281b031..8e7ba0e62cf5 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -50,14 +50,11 @@ static int ieee80211_add_iface(struct wiphy *wiphy, char *name,
 	struct ieee80211_sub_if_data *sdata;
 	int err;
 
-	if (unlikely(local->reg_state != IEEE80211_DEV_REGISTERED))
-		return -ENODEV;
-
 	itype = nl80211_type_to_mac80211_type(type);
 	if (itype == IEEE80211_IF_TYPE_INVALID)
 		return -EINVAL;
 
-	err = ieee80211_if_add(local->mdev, name, &dev, itype, params);
+	err = ieee80211_if_add(local, name, &dev, itype, params);
 	if (err || itype != IEEE80211_IF_TYPE_MNTR || !flags)
 		return err;
 
@@ -68,54 +65,41 @@ static int ieee80211_add_iface(struct wiphy *wiphy, char *name,
 
 static int ieee80211_del_iface(struct wiphy *wiphy, int ifindex)
 {
-	struct ieee80211_local *local = wiphy_priv(wiphy);
 	struct net_device *dev;
-	char *name;
-
-	if (unlikely(local->reg_state != IEEE80211_DEV_REGISTERED))
-		return -ENODEV;
 
 	/* we're under RTNL */
 	dev = __dev_get_by_index(&init_net, ifindex);
 	if (!dev)
-		return 0;
+		return -ENODEV;
 
-	name = dev->name;
+	ieee80211_if_remove(dev);
 
-	return ieee80211_if_remove(local->mdev, name, -1);
+	return 0;
 }
 
 static int ieee80211_change_iface(struct wiphy *wiphy, int ifindex,
 				  enum nl80211_iftype type, u32 *flags,
 				  struct vif_params *params)
 {
-	struct ieee80211_local *local = wiphy_priv(wiphy);
 	struct net_device *dev;
 	enum ieee80211_if_types itype;
 	struct ieee80211_sub_if_data *sdata;
-
-	if (unlikely(local->reg_state != IEEE80211_DEV_REGISTERED))
-		return -ENODEV;
+	int ret;
 
 	/* we're under RTNL */
 	dev = __dev_get_by_index(&init_net, ifindex);
 	if (!dev)
 		return -ENODEV;
 
-	if (netif_running(dev))
-		return -EBUSY;
-
 	itype = nl80211_type_to_mac80211_type(type);
 	if (itype == IEEE80211_IF_TYPE_INVALID)
 		return -EINVAL;
 
 	sdata = IEEE80211_DEV_TO_SUB_IF(dev);
 
-	if (sdata->vif.type == IEEE80211_IF_TYPE_VLAN)
-		return -EOPNOTSUPP;
-
-	ieee80211_if_reinit(dev);
-	ieee80211_if_set_type(dev, itype);
+	ret = ieee80211_if_change_type(sdata, itype);
+	if (ret)
+		return ret;
 
 	if (ieee80211_vif_is_mesh(&sdata->vif) && params->mesh_id_len)
 		ieee80211_if_sta_set_mesh_id(&sdata->u.sta,
@@ -485,7 +469,7 @@ static int ieee80211_config_beacon(struct ieee80211_sub_if_data *sdata,
 
 	kfree(old);
 
-	return ieee80211_if_config_beacon(sdata->dev);
+	return ieee80211_if_config(sdata, IEEE80211_IFCC_BEACON);
 }
 
 static int ieee80211_add_beacon(struct wiphy *wiphy, struct net_device *dev,
@@ -539,7 +523,7 @@ static int ieee80211_del_beacon(struct wiphy *wiphy, struct net_device *dev)
 	synchronize_rcu();
 	kfree(old);
 
-	return ieee80211_if_config_beacon(dev);
+	return ieee80211_if_config(sdata, IEEE80211_IFCC_BEACON);
 }
 
 /* Layer 2 Update frame (802.2 Type 1 LLC XID Update response) */
diff --git a/net/mac80211/debugfs.c b/net/mac80211/debugfs.c
index d20d90eead1f..ee509f1109e2 100644
--- a/net/mac80211/debugfs.c
+++ b/net/mac80211/debugfs.c
@@ -70,16 +70,6 @@ DEBUGFS_READONLY_FILE(rate_ctrl_alg, 100, "%s",
 
 /* statistics stuff */
 
-static inline int rtnl_lock_local(struct ieee80211_local *local)
-{
-	rtnl_lock();
-	if (unlikely(local->reg_state != IEEE80211_DEV_REGISTERED)) {
-		rtnl_unlock();
-		return -ENODEV;
-	}
-	return 0;
-}
-
 #define DEBUGFS_STATS_FILE(name, buflen, fmt, value...)			\
 	DEBUGFS_READONLY_FILE(stats_ ##name, buflen, fmt, ##value)
 
@@ -96,10 +86,7 @@ static ssize_t format_devstat_counter(struct ieee80211_local *local,
 	if (!local->ops->get_stats)
 		return -EOPNOTSUPP;
 
-	res = rtnl_lock_local(local);
-	if (res)
-		return res;
-
+	rtnl_lock();
 	res = local->ops->get_stats(local_to_hw(local), &stats);
 	rtnl_unlock();
 	if (!res)
diff --git a/net/mac80211/debugfs_netdev.c b/net/mac80211/debugfs_netdev.c
index b2089b2da48a..475f89a8aee1 100644
--- a/net/mac80211/debugfs_netdev.c
+++ b/net/mac80211/debugfs_netdev.c
@@ -156,6 +156,8 @@ static const struct file_operations name##_ops = {			\
 
 /* common attributes */
 IEEE80211_IF_FILE(drop_unencrypted, drop_unencrypted, DEC);
+IEEE80211_IF_FILE(force_unicast_rateidx, force_unicast_rateidx, DEC);
+IEEE80211_IF_FILE(max_ratectrl_rateidx, max_ratectrl_rateidx, DEC);
 
 /* STA/IBSS attributes */
 IEEE80211_IF_FILE(state, u.sta.state, DEC);
@@ -191,8 +193,6 @@ __IEEE80211_IF_FILE(flags);
 IEEE80211_IF_FILE(num_sta_ps, u.ap.num_sta_ps, ATOMIC);
 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);
-IEEE80211_IF_FILE(max_ratectrl_rateidx, u.ap.max_ratectrl_rateidx, DEC);
 
 static ssize_t ieee80211_if_fmt_num_buffered_multicast(
 	const struct ieee80211_sub_if_data *sdata, char *buf, int buflen)
@@ -248,6 +248,9 @@ IEEE80211_IF_WFILE(min_discovery_timeout,
 static void add_sta_files(struct ieee80211_sub_if_data *sdata)
 {
 	DEBUGFS_ADD(drop_unencrypted, sta);
+	DEBUGFS_ADD(force_unicast_rateidx, ap);
+	DEBUGFS_ADD(max_ratectrl_rateidx, ap);
+
 	DEBUGFS_ADD(state, sta);
 	DEBUGFS_ADD(bssid, sta);
 	DEBUGFS_ADD(prev_bssid, sta);
@@ -268,23 +271,29 @@ static void add_sta_files(struct ieee80211_sub_if_data *sdata)
 static void add_ap_files(struct ieee80211_sub_if_data *sdata)
 {
 	DEBUGFS_ADD(drop_unencrypted, ap);
+	DEBUGFS_ADD(force_unicast_rateidx, ap);
+	DEBUGFS_ADD(max_ratectrl_rateidx, ap);
+
 	DEBUGFS_ADD(num_sta_ps, 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);
 }
 
 static void add_wds_files(struct ieee80211_sub_if_data *sdata)
 {
 	DEBUGFS_ADD(drop_unencrypted, wds);
+	DEBUGFS_ADD(force_unicast_rateidx, ap);
+	DEBUGFS_ADD(max_ratectrl_rateidx, ap);
+
 	DEBUGFS_ADD(peer, wds);
 }
 
 static void add_vlan_files(struct ieee80211_sub_if_data *sdata)
 {
 	DEBUGFS_ADD(drop_unencrypted, vlan);
+	DEBUGFS_ADD(force_unicast_rateidx, ap);
+	DEBUGFS_ADD(max_ratectrl_rateidx, ap);
 }
 
 static void add_monitor_files(struct ieee80211_sub_if_data *sdata)
@@ -372,6 +381,9 @@ static void add_files(struct ieee80211_sub_if_data *sdata)
 static void del_sta_files(struct ieee80211_sub_if_data *sdata)
 {
 	DEBUGFS_DEL(drop_unencrypted, sta);
+	DEBUGFS_DEL(force_unicast_rateidx, ap);
+	DEBUGFS_DEL(max_ratectrl_rateidx, ap);
+
 	DEBUGFS_DEL(state, sta);
 	DEBUGFS_DEL(bssid, sta);
 	DEBUGFS_DEL(prev_bssid, sta);
@@ -392,23 +404,29 @@ static void del_sta_files(struct ieee80211_sub_if_data *sdata)
 static void del_ap_files(struct ieee80211_sub_if_data *sdata)
 {
 	DEBUGFS_DEL(drop_unencrypted, ap);
+	DEBUGFS_DEL(force_unicast_rateidx, ap);
+	DEBUGFS_DEL(max_ratectrl_rateidx, ap);
+
 	DEBUGFS_DEL(num_sta_ps, 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);
 }
 
 static void del_wds_files(struct ieee80211_sub_if_data *sdata)
 {
 	DEBUGFS_DEL(drop_unencrypted, wds);
+	DEBUGFS_DEL(force_unicast_rateidx, ap);
+	DEBUGFS_DEL(max_ratectrl_rateidx, ap);
+
 	DEBUGFS_DEL(peer, wds);
 }
 
 static void del_vlan_files(struct ieee80211_sub_if_data *sdata)
 {
 	DEBUGFS_DEL(drop_unencrypted, vlan);
+	DEBUGFS_DEL(force_unicast_rateidx, ap);
+	DEBUGFS_DEL(max_ratectrl_rateidx, ap);
 }
 
 static void del_monitor_files(struct ieee80211_sub_if_data *sdata)
@@ -458,12 +476,12 @@ static void del_mesh_config(struct ieee80211_sub_if_data *sdata)
 }
 #endif
 
-static void del_files(struct ieee80211_sub_if_data *sdata, int type)
+static void del_files(struct ieee80211_sub_if_data *sdata)
 {
 	if (!sdata->debugfsdir)
 		return;
 
-	switch (type) {
+	switch (sdata->vif.type) {
 	case IEEE80211_IF_TYPE_MESH_POINT:
 #ifdef CONFIG_MAC80211_MESH
 		del_mesh_stats(sdata);
@@ -503,29 +521,23 @@ void ieee80211_debugfs_add_netdev(struct ieee80211_sub_if_data *sdata)
 	sprintf(buf, "netdev:%s", sdata->dev->name);
 	sdata->debugfsdir = debugfs_create_dir(buf,
 		sdata->local->hw.wiphy->debugfsdir);
+	add_files(sdata);
 }
 
 void ieee80211_debugfs_remove_netdev(struct ieee80211_sub_if_data *sdata)
 {
-	del_files(sdata, sdata->vif.type);
+	del_files(sdata);
 	debugfs_remove(sdata->debugfsdir);
 	sdata->debugfsdir = NULL;
 }
 
-void ieee80211_debugfs_change_if_type(struct ieee80211_sub_if_data *sdata,
-				      int oldtype)
-{
-	del_files(sdata, oldtype);
-	add_files(sdata);
-}
-
 static int netdev_notify(struct notifier_block *nb,
 			 unsigned long state,
 			 void *ndev)
 {
 	struct net_device *dev = ndev;
 	struct dentry *dir;
-	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+	struct ieee80211_sub_if_data *sdata;
 	char buf[10+IFNAMSIZ];
 
 	if (state != NETDEV_CHANGENAME)
@@ -537,6 +549,8 @@ static int netdev_notify(struct notifier_block *nb,
 	if (dev->ieee80211_ptr->wiphy->privid != mac80211_wiphy_privid)
 		return 0;
 
+	sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+
 	sprintf(buf, "netdev:%s", dev->name);
 	dir = sdata->debugfsdir;
 	if (!debugfs_rename(dir->d_parent, dir, dir->d_parent, buf))
diff --git a/net/mac80211/debugfs_netdev.h b/net/mac80211/debugfs_netdev.h
index a690071fde8a..7af731f0b731 100644
--- a/net/mac80211/debugfs_netdev.h
+++ b/net/mac80211/debugfs_netdev.h
@@ -6,8 +6,6 @@
 #ifdef CONFIG_MAC80211_DEBUGFS
 void ieee80211_debugfs_add_netdev(struct ieee80211_sub_if_data *sdata);
 void ieee80211_debugfs_remove_netdev(struct ieee80211_sub_if_data *sdata);
-void ieee80211_debugfs_change_if_type(struct ieee80211_sub_if_data *sdata,
-				     int oldtype);
 void ieee80211_debugfs_netdev_init(void);
 void ieee80211_debugfs_netdev_exit(void);
 #else
@@ -17,9 +15,6 @@ static inline void ieee80211_debugfs_add_netdev(
 static inline void ieee80211_debugfs_remove_netdev(
 	struct ieee80211_sub_if_data *sdata)
 {}
-static inline void ieee80211_debugfs_change_if_type(
-	struct ieee80211_sub_if_data *sdata, int oldtype)
-{}
 static inline void ieee80211_debugfs_netdev_init(void)
 {}
 
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 02a8753a4eca..cbea0154ee3a 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -237,8 +237,6 @@ struct ieee80211_if_ap {
 	struct sk_buff_head ps_bc_buf;
 	atomic_t num_sta_ps; /* number of stations in PS mode */
 	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 */
 };
 
@@ -248,7 +246,6 @@ struct ieee80211_if_wds {
 };
 
 struct ieee80211_if_vlan {
-	struct ieee80211_sub_if_data *ap;
 	struct list_head list;
 };
 
@@ -422,8 +419,6 @@ struct ieee80211_sub_if_data {
 	 */
 	u64 basic_rates;
 
-	u16 sequence;
-
 	/* Fragment table for host-based reassembly */
 	struct ieee80211_fragment_entry	fragments[IEEE80211_FRAGMENT_MAX];
 	unsigned int fragment_next;
@@ -432,16 +427,18 @@ struct ieee80211_sub_if_data {
 	struct ieee80211_key *keys[NUM_DEFAULT_KEYS];
 	struct ieee80211_key *default_key;
 
+	/* BSS configuration for this interface. */
+	struct ieee80211_bss_conf bss_conf;
+
 	/*
-	 * 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.
+	 * AP this belongs to: self in AP mode and
+	 * corresponding AP in VLAN mode, NULL for
+	 * all others (might be needed later in IBSS)
 	 */
-	struct ieee80211_bss_conf bss_conf;
-	struct ieee80211_if_ap *bss; /* BSS that this device belongs to */
+	struct ieee80211_if_ap *bss;
+
+	int force_unicast_rateidx; /* forced TX rateidx for unicast frames */
+	int max_ratectrl_rateidx; /* max TX rateidx for rate control */
 
 	union {
 		struct ieee80211_if_ap ap;
@@ -533,8 +530,6 @@ 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,
@@ -561,12 +556,6 @@ struct ieee80211_local {
 	bool tim_in_locked_section; /* see ieee80211_beacon_get() */
 	int tx_headroom; /* required headroom for hardware/radiotap */
 
-	enum {
-		IEEE80211_DEV_UNINITIALIZED = 0,
-		IEEE80211_DEV_REGISTERED,
-		IEEE80211_DEV_UNREGISTERED,
-	} reg_state;
-
 	/* Tasklet and skb queue to process calls from IRQ mode. All frames
 	 * added to skb_queue will be processed, but frames in
 	 * skb_queue_unreliable may be dropped if the total length of these
@@ -760,6 +749,16 @@ static inline int ieee80211_is_multiqueue(struct ieee80211_local *local)
 #endif
 }
 
+static inline struct ieee80211_sub_if_data *
+IEEE80211_DEV_TO_SUB_IF(struct net_device *dev)
+{
+	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+
+	BUG_ON(!local || local->mdev == dev);
+
+	return netdev_priv(dev);
+}
+
 /* this struct represents 802.11n's RA/TID combination */
 struct ieee80211_ra_tid {
 	u8 ra[ETH_ALEN];
@@ -853,10 +852,8 @@ static inline int ieee80211_bssid_match(const u8 *raddr, const u8 *addr)
 
 /* ieee80211.c */
 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);
+int ieee80211_if_config(struct ieee80211_sub_if_data *sdata, u32 changed);
 void ieee80211_tx_set_protected(struct ieee80211_tx_data *tx);
-void ieee80211_if_setup(struct net_device *dev);
 u32 ieee80211_handle_ht(struct ieee80211_local *local, int enable_ht,
 			struct ieee80211_ht_info *req_ht_cap,
 			struct ieee80211_ht_bss_info *req_bss_cap);
@@ -883,8 +880,8 @@ int ieee80211_sta_scan_results(struct net_device *dev,
 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);
+void ieee80211_rx_bss_list_init(struct ieee80211_local *local);
+void ieee80211_rx_bss_list_deinit(struct ieee80211_local *local);
 int ieee80211_sta_set_extra_ie(struct net_device *dev, char *ie, size_t len);
 struct sta_info *ieee80211_ibss_add_sta(struct net_device *dev,
 					struct sk_buff *skb, u8 *bssid,
@@ -925,17 +922,15 @@ static inline void ieee80211_start_mesh(struct net_device *dev)
 {}
 #endif
 
-/* ieee80211_iface.c */
-int ieee80211_if_add(struct net_device *dev, const char *name,
-		     struct net_device **new_dev, int type,
+/* interface handling */
+void ieee80211_if_setup(struct net_device *dev);
+int ieee80211_if_add(struct ieee80211_local *local, const char *name,
+		     struct net_device **new_dev, enum ieee80211_if_types type,
 		     struct vif_params *params);
-void ieee80211_if_set_type(struct net_device *dev, int type);
-void ieee80211_if_reinit(struct net_device *dev);
-void __ieee80211_if_del(struct ieee80211_local *local,
-			struct ieee80211_sub_if_data *sdata);
-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_change_type(struct ieee80211_sub_if_data *sdata,
+			     enum ieee80211_if_types type);
+void ieee80211_if_remove(struct net_device *dev);
+void ieee80211_remove_interfaces(struct ieee80211_local *local);
 
 /* tx handling */
 void ieee80211_clear_tx_pending(struct ieee80211_local *local);
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c
index eeb16926aa7d..610ed1d9893a 100644
--- a/net/mac80211/iface.c
+++ b/net/mac80211/iface.c
@@ -2,6 +2,7 @@
  * Copyright 2002-2005, Instant802 Networks, Inc.
  * Copyright 2005-2006, Devicescape Software, Inc.
  * Copyright (c) 2006 Jiri Benc <jbenc@suse.cz>
+ * Copyright 2008, 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
@@ -17,145 +18,91 @@
 #include "debugfs_netdev.h"
 #include "mesh.h"
 
-void ieee80211_if_sdata_init(struct ieee80211_sub_if_data *sdata)
+/*
+ * Called when the netdev is removed or, by the code below, before
+ * the interface type changes.
+ */
+static void ieee80211_teardown_sdata(struct net_device *dev)
 {
+	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+	struct ieee80211_local *local = sdata->local;
+	struct beacon_data *beacon;
+	struct sk_buff *skb;
+	int flushed;
 	int i;
 
-	/* Default values for sub-interface parameters */
-	sdata->drop_unencrypted = 0;
-	for (i = 0; i < IEEE80211_FRAGMENT_MAX; i++)
-		skb_queue_head_init(&sdata->fragments[i].skb_list);
-
-	INIT_LIST_HEAD(&sdata->key_list);
-}
+	ieee80211_debugfs_remove_netdev(sdata);
 
-static void ieee80211_if_sdata_deinit(struct ieee80211_sub_if_data *sdata)
-{
-	int i;
+	/* free extra data */
+	ieee80211_free_keys(sdata);
 
 	for (i = 0; i < IEEE80211_FRAGMENT_MAX; i++)
 		__skb_queue_purge(&sdata->fragments[i].skb_list);
-}
-
-/* Must be called with rtnl lock held. */
-int ieee80211_if_add(struct net_device *dev, const char *name,
-		     struct net_device **new_dev, int type,
-		     struct vif_params *params)
-{
-	struct net_device *ndev;
-	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
-	struct ieee80211_sub_if_data *sdata = NULL;
-	int ret;
-
-	ASSERT_RTNL();
-	ndev = alloc_netdev(sizeof(*sdata) + local->hw.vif_data_size,
-			    name, ieee80211_if_setup);
-	if (!ndev)
-		return -ENOMEM;
+	sdata->fragment_next = 0;
 
-	ndev->needed_headroom = local->tx_headroom +
-				4*6 /* four MAC addresses */
-				+ 2 + 2 + 2 + 2 /* ctl, dur, seq, qos */
-				+ 6 /* mesh */
-				+ 8 /* rfc1042/bridge tunnel */
-				- ETH_HLEN /* ethernet hard_header_len */
-				+ IEEE80211_ENCRYPT_HEADROOM;
-	ndev->needed_tailroom = IEEE80211_ENCRYPT_TAILROOM;
-
-	ret = dev_alloc_name(ndev, ndev->name);
-	if (ret < 0)
-		goto fail;
-
-	memcpy(ndev->dev_addr, local->hw.wiphy->perm_addr, ETH_ALEN);
-	ndev->base_addr = dev->base_addr;
-	ndev->irq = dev->irq;
-	ndev->mem_start = dev->mem_start;
-	ndev->mem_end = dev->mem_end;
-	SET_NETDEV_DEV(ndev, wiphy_dev(local->hw.wiphy));
-
-	sdata = IEEE80211_DEV_TO_SUB_IF(ndev);
-	ndev->ieee80211_ptr = &sdata->wdev;
-	sdata->wdev.wiphy = local->hw.wiphy;
-	sdata->vif.type = IEEE80211_IF_TYPE_AP;
-	sdata->dev = ndev;
-	sdata->local = local;
-	ieee80211_if_sdata_init(sdata);
-
-	ret = register_netdevice(ndev);
-	if (ret)
-		goto fail;
-
-	ieee80211_debugfs_add_netdev(sdata);
-	ieee80211_if_set_type(ndev, type);
+	switch (sdata->vif.type) {
+	case IEEE80211_IF_TYPE_AP:
+		beacon = sdata->u.ap.beacon;
+		rcu_assign_pointer(sdata->u.ap.beacon, NULL);
+		synchronize_rcu();
+		kfree(beacon);
 
-	if (ieee80211_vif_is_mesh(&sdata->vif) &&
-	    params && params->mesh_id_len)
-		ieee80211_if_sta_set_mesh_id(&sdata->u.sta,
-					     params->mesh_id_len,
-					     params->mesh_id);
+		while ((skb = skb_dequeue(&sdata->u.ap.ps_bc_buf))) {
+			local->total_ps_buffered--;
+			dev_kfree_skb(skb);
+		}
 
-	/* we're under RTNL so all this is fine */
-	if (unlikely(local->reg_state == IEEE80211_DEV_UNREGISTERED)) {
-		__ieee80211_if_del(local, sdata);
-		return -ENODEV;
+		break;
+	case IEEE80211_IF_TYPE_MESH_POINT:
+		/* Allow compiler to elide mesh_rmc_free call. */
+		if (ieee80211_vif_is_mesh(&sdata->vif))
+			mesh_rmc_free(dev);
+		/* fall through */
+	case IEEE80211_IF_TYPE_STA:
+	case IEEE80211_IF_TYPE_IBSS:
+		kfree(sdata->u.sta.extra_ie);
+		kfree(sdata->u.sta.assocreq_ies);
+		kfree(sdata->u.sta.assocresp_ies);
+		kfree_skb(sdata->u.sta.probe_resp);
+		break;
+	case IEEE80211_IF_TYPE_WDS:
+	case IEEE80211_IF_TYPE_VLAN:
+	case IEEE80211_IF_TYPE_MNTR:
+		break;
+	case IEEE80211_IF_TYPE_INVALID:
+		BUG();
+		break;
 	}
-	list_add_tail_rcu(&sdata->list, &local->interfaces);
 
-	if (new_dev)
-		*new_dev = ndev;
-
-	return 0;
-
-fail:
-	free_netdev(ndev);
-	return ret;
+	flushed = sta_info_flush(local, sdata);
+	WARN_ON(flushed);
 }
 
-void ieee80211_if_set_type(struct net_device *dev, int type)
+/*
+ * Helper function to initialise an interface to a specific type.
+ */
+static void ieee80211_setup_sdata(struct ieee80211_sub_if_data *sdata,
+				  enum ieee80211_if_types type)
 {
-	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-	int oldtype = sdata->vif.type;
-
-	/*
-	 * We need to call this function on the master interface
-	 * which already has a hard_start_xmit routine assigned
-	 * which must not be changed.
-	 */
-	if (dev != sdata->local->mdev)
-		dev->hard_start_xmit = ieee80211_subif_start_xmit;
+	struct ieee80211_if_sta *ifsta;
 
-	/*
-	 * Called even when register_netdevice fails, it would
-	 * oops if assigned before initialising the rest.
-	 */
-	dev->uninit = ieee80211_if_reinit;
+	/* clear type-dependent union */
+	memset(&sdata->u, 0, sizeof(sdata->u));
 
-	/* most have no BSS pointer */
-	sdata->bss = NULL;
+	/* and set some type-dependent values */
 	sdata->vif.type = type;
 
-	sdata->basic_rates = 0;
+	/* only monitor differs */
+	sdata->dev->type = ARPHRD_ETHER;
 
 	switch (type) {
-	case IEEE80211_IF_TYPE_WDS:
-		/* nothing special */
-		break;
-	case IEEE80211_IF_TYPE_VLAN:
-		sdata->u.vlan.ap = NULL;
-		break;
 	case IEEE80211_IF_TYPE_AP:
-		sdata->u.ap.force_unicast_rateidx = -1;
-		sdata->u.ap.max_ratectrl_rateidx = -1;
 		skb_queue_head_init(&sdata->u.ap.ps_bc_buf);
-		sdata->bss = &sdata->u.ap;
 		INIT_LIST_HEAD(&sdata->u.ap.vlans);
 		break;
 	case IEEE80211_IF_TYPE_MESH_POINT:
 	case IEEE80211_IF_TYPE_STA:
-	case IEEE80211_IF_TYPE_IBSS: {
-		struct ieee80211_sub_if_data *msdata;
-		struct ieee80211_if_sta *ifsta;
-
+	case IEEE80211_IF_TYPE_IBSS:
 		ifsta = &sdata->u.sta;
 		INIT_WORK(&ifsta->work, ieee80211_sta_work);
 		setup_timer(&ifsta->timer, ieee80211_sta_timer,
@@ -171,153 +118,152 @@ void ieee80211_if_set_type(struct net_device *dev, int type)
 		if (ieee80211_num_regular_queues(&sdata->local->hw) >= 4)
 			ifsta->flags |= IEEE80211_STA_WMM_ENABLED;
 
-		msdata = IEEE80211_DEV_TO_SUB_IF(sdata->local->mdev);
-		sdata->bss = &msdata->u.ap;
-
 		if (ieee80211_vif_is_mesh(&sdata->vif))
 			ieee80211_mesh_init_sdata(sdata);
 		break;
-	}
 	case IEEE80211_IF_TYPE_MNTR:
-		dev->type = ARPHRD_IEEE80211_RADIOTAP;
-		dev->hard_start_xmit = ieee80211_monitor_start_xmit;
+		sdata->dev->type = ARPHRD_IEEE80211_RADIOTAP;
+		sdata->dev->hard_start_xmit = ieee80211_monitor_start_xmit;
 		sdata->u.mntr_flags = MONITOR_FLAG_CONTROL |
 				      MONITOR_FLAG_OTHER_BSS;
 		break;
+	case IEEE80211_IF_TYPE_WDS:
+	case IEEE80211_IF_TYPE_VLAN:
+		break;
 	case IEEE80211_IF_TYPE_INVALID:
 		BUG();
 		break;
 	}
-	ieee80211_debugfs_change_if_type(sdata, oldtype);
+
+	ieee80211_debugfs_add_netdev(sdata);
 }
 
-/* Must be called with rtnl lock held. */
-void ieee80211_if_reinit(struct net_device *dev)
+int ieee80211_if_change_type(struct ieee80211_sub_if_data *sdata,
+			     enum ieee80211_if_types type)
 {
-	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
-	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-	struct sk_buff *skb;
-	int flushed;
+	ASSERT_RTNL();
+
+	if (type == sdata->vif.type)
+		return 0;
+
+	/*
+	 * We could, here, on changes between IBSS/STA/MESH modes,
+	 * invoke an MLME function instead that disassociates etc.
+	 * and goes into the requested mode.
+	 */
+
+	if (netif_running(sdata->dev))
+		return -EBUSY;
+
+	/* Purge and reset type-dependent state. */
+	ieee80211_teardown_sdata(sdata->dev);
+	ieee80211_setup_sdata(sdata, type);
+
+	/* reset some values that shouldn't be kept across type changes */
+	sdata->basic_rates = 0;
+	sdata->drop_unencrypted = 0;
+
+	return 0;
+}
+
+int ieee80211_if_add(struct ieee80211_local *local, const char *name,
+		     struct net_device **new_dev, enum ieee80211_if_types type,
+		     struct vif_params *params)
+{
+	struct net_device *ndev;
+	struct ieee80211_sub_if_data *sdata = NULL;
+	int ret, i;
 
 	ASSERT_RTNL();
 
-	ieee80211_free_keys(sdata);
+	ndev = alloc_netdev(sizeof(*sdata) + local->hw.vif_data_size,
+			    name, ieee80211_if_setup);
+	if (!ndev)
+		return -ENOMEM;
 
-	ieee80211_if_sdata_deinit(sdata);
+	ndev->needed_headroom = local->tx_headroom +
+				4*6 /* four MAC addresses */
+				+ 2 + 2 + 2 + 2 /* ctl, dur, seq, qos */
+				+ 6 /* mesh */
+				+ 8 /* rfc1042/bridge tunnel */
+				- ETH_HLEN /* ethernet hard_header_len */
+				+ IEEE80211_ENCRYPT_HEADROOM;
+	ndev->needed_tailroom = IEEE80211_ENCRYPT_TAILROOM;
 
-	/* Need to handle mesh specially to allow eliding the function call */
-	if (ieee80211_vif_is_mesh(&sdata->vif))
-		mesh_rmc_free(dev);
+	ret = dev_alloc_name(ndev, ndev->name);
+	if (ret < 0)
+		goto fail;
 
-	switch (sdata->vif.type) {
-	case IEEE80211_IF_TYPE_INVALID:
-		/* cannot happen */
-		WARN_ON(1);
-		break;
-	case IEEE80211_IF_TYPE_AP: {
-		/* Remove all virtual interfaces that use this BSS
-		 * as their sdata->bss */
-		struct ieee80211_sub_if_data *tsdata, *n;
-		struct beacon_data *beacon;
-
-		list_for_each_entry_safe(tsdata, n, &local->interfaces, list) {
-			if (tsdata != sdata && tsdata->bss == &sdata->u.ap) {
-				printk(KERN_DEBUG "%s: removing virtual "
-				       "interface %s because its BSS interface"
-				       " is being removed\n",
-				       sdata->dev->name, tsdata->dev->name);
-				list_del_rcu(&tsdata->list);
-				/*
-				 * We have lots of time and can afford
-				 * to sync for each interface
-				 */
-				synchronize_rcu();
-				__ieee80211_if_del(local, tsdata);
-			}
-		}
+	memcpy(ndev->dev_addr, local->hw.wiphy->perm_addr, ETH_ALEN);
+	SET_NETDEV_DEV(ndev, wiphy_dev(local->hw.wiphy));
 
-		beacon = sdata->u.ap.beacon;
-		rcu_assign_pointer(sdata->u.ap.beacon, NULL);
-		synchronize_rcu();
-		kfree(beacon);
+	/* don't use IEEE80211_DEV_TO_SUB_IF because it checks too much */
+	sdata = netdev_priv(ndev);
+	ndev->ieee80211_ptr = &sdata->wdev;
 
-		while ((skb = skb_dequeue(&sdata->u.ap.ps_bc_buf))) {
-			local->total_ps_buffered--;
-			dev_kfree_skb(skb);
-		}
+	/* initialise type-independent data */
+	sdata->wdev.wiphy = local->hw.wiphy;
+	sdata->local = local;
+	sdata->dev = ndev;
 
-		break;
-	}
-	case IEEE80211_IF_TYPE_WDS:
-		/* nothing to do */
-		break;
-	case IEEE80211_IF_TYPE_MESH_POINT:
-	case IEEE80211_IF_TYPE_STA:
-	case IEEE80211_IF_TYPE_IBSS:
-		kfree(sdata->u.sta.extra_ie);
-		sdata->u.sta.extra_ie = NULL;
-		kfree(sdata->u.sta.assocreq_ies);
-		sdata->u.sta.assocreq_ies = NULL;
-		kfree(sdata->u.sta.assocresp_ies);
-		sdata->u.sta.assocresp_ies = NULL;
-		if (sdata->u.sta.probe_resp) {
-			dev_kfree_skb(sdata->u.sta.probe_resp);
-			sdata->u.sta.probe_resp = NULL;
-		}
+	for (i = 0; i < IEEE80211_FRAGMENT_MAX; i++)
+		skb_queue_head_init(&sdata->fragments[i].skb_list);
 
-		break;
-	case IEEE80211_IF_TYPE_MNTR:
-		dev->type = ARPHRD_ETHER;
-		break;
-	case IEEE80211_IF_TYPE_VLAN:
-		sdata->u.vlan.ap = NULL;
-		break;
-	}
+	INIT_LIST_HEAD(&sdata->key_list);
 
-	flushed = sta_info_flush(local, sdata);
-	WARN_ON(flushed);
+	sdata->force_unicast_rateidx = -1;
+	sdata->max_ratectrl_rateidx = -1;
 
-	memset(&sdata->u, 0, sizeof(sdata->u));
-	ieee80211_if_sdata_init(sdata);
-}
+	/* setup type-dependent data */
+	ieee80211_setup_sdata(sdata, type);
 
-/* Must be called with rtnl lock held. */
-void __ieee80211_if_del(struct ieee80211_local *local,
-			struct ieee80211_sub_if_data *sdata)
-{
-	struct net_device *dev = sdata->dev;
+	ret = register_netdevice(ndev);
+	if (ret)
+		goto fail;
 
-	ieee80211_debugfs_remove_netdev(sdata);
-	unregister_netdevice(dev);
-	/* Except master interface, the net_device will be freed by
-	 * net_device->destructor (i. e. ieee80211_if_free). */
+	ndev->uninit = ieee80211_teardown_sdata;
+
+	if (ieee80211_vif_is_mesh(&sdata->vif) &&
+	    params && params->mesh_id_len)
+		ieee80211_if_sta_set_mesh_id(&sdata->u.sta,
+					     params->mesh_id_len,
+					     params->mesh_id);
+
+	list_add_tail_rcu(&sdata->list, &local->interfaces);
+
+	if (new_dev)
+		*new_dev = ndev;
+
+	return 0;
+
+ fail:
+	free_netdev(ndev);
+	return ret;
 }
 
-/* Must be called with rtnl lock held. */
-int ieee80211_if_remove(struct net_device *dev, const char *name, int id)
+void ieee80211_if_remove(struct net_device *dev)
 {
-	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
-	struct ieee80211_sub_if_data *sdata, *n;
+	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
 
 	ASSERT_RTNL();
 
-	list_for_each_entry_safe(sdata, n, &local->interfaces, list) {
-		if ((sdata->vif.type == id || id == -1) &&
-		    strcmp(name, sdata->dev->name) == 0 &&
-		    sdata->dev != local->mdev) {
-			list_del_rcu(&sdata->list);
-			synchronize_rcu();
-			__ieee80211_if_del(local, sdata);
-			return 0;
-		}
-	}
-	return -ENODEV;
+	list_del_rcu(&sdata->list);
+	synchronize_rcu();
+	unregister_netdevice(dev);
 }
 
-void ieee80211_if_free(struct net_device *dev)
+/*
+ * Remove all interfaces, may only be called at hardware unregistration
+ * time because it doesn't do RCU-safe list removals.
+ */
+void ieee80211_remove_interfaces(struct ieee80211_local *local)
 {
-	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+	struct ieee80211_sub_if_data *sdata, *tmp;
 
-	ieee80211_if_sdata_deinit(sdata);
-	free_netdev(dev);
+	ASSERT_RTNL();
+
+	list_for_each_entry_safe(sdata, tmp, &local->interfaces, list) {
+		list_del(&sdata->list);
+		unregister_netdevice(sdata->dev);
+	}
 }
diff --git a/net/mac80211/main.c b/net/mac80211/main.c
index 1c4d3ba6b878..36859e794928 100644
--- a/net/mac80211/main.c
+++ b/net/mac80211/main.c
@@ -105,7 +105,7 @@ static int ieee80211_master_open(struct net_device *dev)
 
 	/* we hold the RTNL here so can safely walk the list */
 	list_for_each_entry(sdata, &local->interfaces, list) {
-		if (sdata->dev != dev && netif_running(sdata->dev)) {
+		if (netif_running(sdata->dev)) {
 			res = 0;
 			break;
 		}
@@ -126,7 +126,7 @@ static int ieee80211_master_stop(struct net_device *dev)
 
 	/* we hold the RTNL here so can safely walk the list */
 	list_for_each_entry(sdata, &local->interfaces, list)
-		if (sdata->dev != dev && netif_running(sdata->dev))
+		if (netif_running(sdata->dev))
 			dev_close(sdata->dev);
 
 	return 0;
@@ -194,7 +194,7 @@ static int ieee80211_open(struct net_device *dev)
 	list_for_each_entry(nsdata, &local->interfaces, list) {
 		struct net_device *ndev = nsdata->dev;
 
-		if (ndev != dev && ndev != local->mdev && netif_running(ndev)) {
+		if (ndev != dev && netif_running(ndev)) {
 			/*
 			 * Allow only a single IBSS interface to be up at any
 			 * time. This is restricted because beacon distribution
@@ -210,30 +210,6 @@ static int ieee80211_open(struct net_device *dev)
 				return -EBUSY;
 
 			/*
-			 * Disallow multiple IBSS/STA mode interfaces.
-			 *
-			 * This is a technical restriction, it is possible although
-			 * most likely not IEEE 802.11 compliant to have multiple
-			 * STAs with just a single hardware (the TSF timer will not
-			 * be adjusted properly.)
-			 *
-			 * However, because mac80211 uses the master device's BSS
-			 * information for each STA/IBSS interface, doing this will
-			 * currently corrupt that BSS information completely, unless,
-			 * a not very useful case, both STAs are associated to the
-			 * same BSS.
-			 *
-			 * To remove this restriction, the BSS information needs to
-			 * be embedded in the STA/IBSS mode sdata instead of using
-			 * the master device's BSS structure.
-			 */
-			if ((sdata->vif.type == IEEE80211_IF_TYPE_STA ||
-			     sdata->vif.type == IEEE80211_IF_TYPE_IBSS) &&
-			    (nsdata->vif.type == IEEE80211_IF_TYPE_STA ||
-			     nsdata->vif.type == IEEE80211_IF_TYPE_IBSS))
-				return -EBUSY;
-
-			/*
 			 * The remaining checks are only performed for interfaces
 			 * with the same MAC address.
 			 */
@@ -252,7 +228,7 @@ static int ieee80211_open(struct net_device *dev)
 			 */
 			if (sdata->vif.type == IEEE80211_IF_TYPE_VLAN &&
 			    nsdata->vif.type == IEEE80211_IF_TYPE_AP)
-				sdata->u.vlan.ap = nsdata;
+				sdata->bss = &nsdata->u.ap;
 		}
 	}
 
@@ -262,10 +238,13 @@ static int ieee80211_open(struct net_device *dev)
 			return -ENOLINK;
 		break;
 	case IEEE80211_IF_TYPE_VLAN:
-		if (!sdata->u.vlan.ap)
+		if (!sdata->bss)
 			return -ENOLINK;
+		list_add(&sdata->u.vlan.list, &sdata->bss->vlans);
 		break;
 	case IEEE80211_IF_TYPE_AP:
+		sdata->bss = &sdata->u.ap;
+		break;
 	case IEEE80211_IF_TYPE_STA:
 	case IEEE80211_IF_TYPE_MNTR:
 	case IEEE80211_IF_TYPE_IBSS:
@@ -283,14 +262,13 @@ static int ieee80211_open(struct net_device *dev)
 		if (local->ops->start)
 			res = local->ops->start(local_to_hw(local));
 		if (res)
-			return res;
+			goto err_del_bss;
 		need_hw_reconfig = 1;
 		ieee80211_led_radio(local, local->hw.conf.radio_enabled);
 	}
 
 	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:
@@ -329,7 +307,8 @@ static int ieee80211_open(struct net_device *dev)
 		if (res)
 			goto err_stop;
 
-		ieee80211_if_config(dev);
+		if (ieee80211_vif_is_mesh(&sdata->vif))
+			ieee80211_start_mesh(sdata->dev);
 		changed |= ieee80211_reset_erp_info(dev);
 		ieee80211_bss_info_change_notify(sdata, changed);
 		ieee80211_enable_keys(sdata);
@@ -404,6 +383,10 @@ static int ieee80211_open(struct net_device *dev)
  err_stop:
 	if (!local->open_count && local->ops->stop)
 		local->ops->stop(local_to_hw(local));
+ err_del_bss:
+	sdata->bss = NULL;
+	if (sdata->vif.type == IEEE80211_IF_TYPE_VLAN)
+		list_del(&sdata->u.vlan.list);
 	return res;
 }
 
@@ -486,7 +469,6 @@ static int ieee80211_stop(struct net_device *dev)
 	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:
@@ -549,6 +531,8 @@ static int ieee80211_stop(struct net_device *dev)
 		local->ops->remove_interface(local_to_hw(local), &conf);
 	}
 
+	sdata->bss = NULL;
+
 	if (local->open_count == 0) {
 		if (netif_running(local->mdev))
 			dev_close(local->mdev);
@@ -988,7 +972,6 @@ static const struct header_ops ieee80211_header_ops = {
 	.cache_update	= eth_header_cache_update,
 };
 
-/* Must not be called for mdev */
 void ieee80211_if_setup(struct net_device *dev)
 {
 	ether_setup(dev);
@@ -998,62 +981,52 @@ void ieee80211_if_setup(struct net_device *dev)
 	dev->change_mtu = ieee80211_change_mtu;
 	dev->open = ieee80211_open;
 	dev->stop = ieee80211_stop;
-	dev->destructor = ieee80211_if_free;
+	dev->destructor = free_netdev;
 }
 
 /* everything else */
 
-static int __ieee80211_if_config(struct net_device *dev,
-				 struct sk_buff *beacon)
+int ieee80211_if_config(struct ieee80211_sub_if_data *sdata, u32 changed)
 {
-	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+	struct ieee80211_local *local = sdata->local;
 	struct ieee80211_if_conf conf;
 
-	if (!local->ops->config_interface || !netif_running(dev))
+	if (WARN_ON(!netif_running(sdata->dev)))
+		return 0;
+
+	if (!local->ops->config_interface)
 		return 0;
 
 	memset(&conf, 0, sizeof(conf));
-	conf.type = sdata->vif.type;
+	conf.changed = changed;
+
 	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 (ieee80211_vif_is_mesh(&sdata->vif)) {
-		conf.beacon = beacon;
-		ieee80211_start_mesh(dev);
 	} else if (sdata->vif.type == IEEE80211_IF_TYPE_AP) {
+		conf.bssid = sdata->dev->dev_addr;
 		conf.ssid = sdata->u.ap.ssid;
 		conf.ssid_len = sdata->u.ap.ssid_len;
-		conf.beacon = beacon;
+	} else if (ieee80211_vif_is_mesh(&sdata->vif)) {
+		u8 zero[ETH_ALEN] = { 0 };
+		conf.bssid = zero;
+		conf.ssid = zero;
+		conf.ssid_len = 0;
+	} else {
+		WARN_ON(1);
+		return -EINVAL;
 	}
-	return local->ops->config_interface(local_to_hw(local),
-					    &sdata->vif, &conf);
-}
 
-int ieee80211_if_config(struct net_device *dev)
-{
-	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
-	if (sdata->vif.type == IEEE80211_IF_TYPE_MESH_POINT &&
-	    (local->hw.flags & IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE))
-		return ieee80211_if_config_beacon(dev);
-	return __ieee80211_if_config(dev, NULL);
-}
+	if (WARN_ON(!conf.bssid && (changed & IEEE80211_IFCC_BSSID)))
+		return -EINVAL;
 
-int ieee80211_if_config_beacon(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);
-	struct sk_buff *skb;
+	if (WARN_ON(!conf.ssid && (changed & IEEE80211_IFCC_SSID)))
+		return -EINVAL;
 
-	if (!(local->hw.flags & IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE))
-		return 0;
-	skb = ieee80211_beacon_get(local_to_hw(local), &sdata->vif);
-	if (!skb)
-		return -ENOMEM;
-	return __ieee80211_if_config(dev, skb);
+	return local->ops->config_interface(local_to_hw(local),
+					    &sdata->vif, &conf);
 }
 
 int ieee80211_hw_config(struct ieee80211_local *local)
@@ -1659,7 +1632,7 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
 	int result;
 	enum ieee80211_band band;
 	struct net_device *mdev;
-	struct ieee80211_sub_if_data *sdata;
+	struct wireless_dev *mwdev;
 
 	/*
 	 * generic code guarantees at least one band,
@@ -1699,8 +1672,7 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
 	hw->ampdu_queues = 0;
 #endif
 
-	/* for now, mdev needs sub_if_data :/ */
-	mdev = alloc_netdev_mq(sizeof(struct ieee80211_sub_if_data),
+	mdev = alloc_netdev_mq(sizeof(struct wireless_dev),
 			       "wmaster%d", ether_setup,
 			       ieee80211_num_queues(hw));
 	if (!mdev)
@@ -1709,13 +1681,13 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
 	if (ieee80211_num_queues(hw) > 1)
 		mdev->features |= NETIF_F_MULTI_QUEUE;
 
-	sdata = IEEE80211_DEV_TO_SUB_IF(mdev);
-	mdev->ieee80211_ptr = &sdata->wdev;
-	sdata->wdev.wiphy = local->hw.wiphy;
+	mwdev = netdev_priv(mdev);
+	mdev->ieee80211_ptr = mwdev;
+	mwdev->wiphy = local->hw.wiphy;
 
 	local->mdev = mdev;
 
-	ieee80211_rx_bss_list_init(mdev);
+	ieee80211_rx_bss_list_init(local);
 
 	mdev->hard_start_xmit = ieee80211_master_start_xmit;
 	mdev->open = ieee80211_master_open;
@@ -1724,16 +1696,6 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
 	mdev->header_ops = &ieee80211_header_ops;
 	mdev->set_multicast_list = ieee80211_master_set_multicast_list;
 
-	sdata->vif.type = IEEE80211_IF_TYPE_AP;
-	sdata->dev = mdev;
-	sdata->local = local;
-	sdata->u.ap.force_unicast_rateidx = -1;
-	sdata->u.ap.max_ratectrl_rateidx = -1;
-	ieee80211_if_sdata_init(sdata);
-
-	/* no RCU needed since we're still during init phase */
-	list_add_tail(&sdata->list, &local->interfaces);
-
 	name = wiphy_dev(local->hw.wiphy)->driver->name;
 	local->hw.workqueue = create_freezeable_workqueue(name);
 	if (!local->hw.workqueue) {
@@ -1779,9 +1741,6 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
 	if (result < 0)
 		goto fail_dev;
 
-	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,
 					      hw->rate_control_algorithm);
 	if (result < 0) {
@@ -1801,13 +1760,12 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
 	ieee80211_install_qdisc(local->mdev);
 
 	/* add one default STA interface */
-	result = ieee80211_if_add(local->mdev, "wlan%d", NULL,
+	result = ieee80211_if_add(local, "wlan%d", NULL,
 				  IEEE80211_IF_TYPE_STA, NULL);
 	if (result)
 		printk(KERN_WARNING "%s: Failed to add default virtual iface\n",
 		       wiphy_name(local->hw.wiphy));
 
-	local->reg_state = IEEE80211_DEV_REGISTERED;
 	rtnl_unlock();
 
 	ieee80211_led_init(local);
@@ -1817,7 +1775,6 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
 fail_wep:
 	rate_control_deinitialize(local);
 fail_rate:
-	ieee80211_debugfs_remove_netdev(IEEE80211_DEV_TO_SUB_IF(local->mdev));
 	unregister_netdevice(local->mdev);
 	local->mdev = NULL;
 fail_dev:
@@ -1827,10 +1784,8 @@ fail_sta_info:
 	debugfs_hw_del(local);
 	destroy_workqueue(local->hw.workqueue);
 fail_workqueue:
-	if (local->mdev != NULL) {
-		ieee80211_if_free(local->mdev);
-		local->mdev = NULL;
-	}
+	if (local->mdev)
+		free_netdev(local->mdev);
 fail_mdev_alloc:
 	wiphy_unregister(local->hw.wiphy);
 	return result;
@@ -1840,42 +1795,27 @@ EXPORT_SYMBOL(ieee80211_register_hw);
 void ieee80211_unregister_hw(struct ieee80211_hw *hw)
 {
 	struct ieee80211_local *local = hw_to_local(hw);
-	struct ieee80211_sub_if_data *sdata, *tmp;
 
 	tasklet_kill(&local->tx_pending_tasklet);
 	tasklet_kill(&local->tasklet);
 
 	rtnl_lock();
 
-	BUG_ON(local->reg_state != IEEE80211_DEV_REGISTERED);
-
-	local->reg_state = IEEE80211_DEV_UNREGISTERED;
-
 	/*
 	 * At this point, interface list manipulations are fine
 	 * because the driver cannot be handing us frames any
 	 * more and the tasklet is killed.
 	 */
 
-	/*
-	 * First, we remove all non-master interfaces. Do this because they
-	 * may have bss pointer dependency on the master, and when we free
-	 * the master these would be freed as well, breaking our list
-	 * iteration completely.
-	 */
-	list_for_each_entry_safe(sdata, tmp, &local->interfaces, list) {
-		if (sdata->dev == local->mdev)
-			continue;
-		list_del(&sdata->list);
-		__ieee80211_if_del(local, sdata);
-	}
+	/* First, we remove all virtual interfaces. */
+	ieee80211_remove_interfaces(local);
 
 	/* then, finally, remove the master interface */
-	__ieee80211_if_del(local, IEEE80211_DEV_TO_SUB_IF(local->mdev));
+	unregister_netdevice(local->mdev);
 
 	rtnl_unlock();
 
-	ieee80211_rx_bss_list_deinit(local->mdev);
+	ieee80211_rx_bss_list_deinit(local);
 	ieee80211_clear_tx_pending(local);
 	sta_info_stop(local);
 	rate_control_deinitialize(local);
@@ -1892,8 +1832,7 @@ void ieee80211_unregister_hw(struct ieee80211_hw *hw)
 	wiphy_unregister(local->hw.wiphy);
 	ieee80211_wep_free(local);
 	ieee80211_led_exit(local);
-	ieee80211_if_free(local->mdev);
-	local->mdev = NULL;
+	free_netdev(local->mdev);
 }
 EXPORT_SYMBOL(ieee80211_unregister_hw);
 
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index dbc8cf454bc0..8f51375317dd 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -78,7 +78,7 @@ static void ieee80211_send_probe_req(struct net_device *dev, u8 *dst,
 static struct ieee80211_sta_bss *
 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,
+static void ieee80211_rx_bss_put(struct ieee80211_local *local,
 				 struct ieee80211_sta_bss *bss);
 static int ieee80211_sta_find_ibss(struct net_device *dev,
 				   struct ieee80211_if_sta *ifsta);
@@ -345,7 +345,7 @@ static void ieee80211_sta_wmm_params(struct net_device *dev,
 		params.aifs = pos[0] & 0x0f;
 		params.cw_max = ecw2cw((pos[1] & 0xf0) >> 4);
 		params.cw_min = ecw2cw(pos[1] & 0x0f);
-		params.txop = pos[2] | (pos[3] << 8);
+		params.txop = get_unaligned_le16(pos + 2);
 #ifdef CONFIG_MAC80211_VERBOSE_DEBUG
 		printk(KERN_DEBUG "%s: WMM queue=%d aci=%d acm=%d aifs=%d "
 		       "cWmin=%d cWmax=%d txop=%d\n",
@@ -554,7 +554,7 @@ static void ieee80211_set_associated(struct net_device *dev,
 
 			changed |= ieee80211_handle_bss_capability(sdata, bss);
 
-			ieee80211_rx_bss_put(dev, bss);
+			ieee80211_rx_bss_put(local, bss);
 		}
 
 		if (conf->flags & IEEE80211_CONF_SUPPORT_HT_MODE) {
@@ -760,7 +760,7 @@ static void ieee80211_send_assoc(struct net_device *dev,
 		    (local->hw.flags & IEEE80211_HW_SPECTRUM_MGMT))
 			capab |= WLAN_CAPABILITY_SPECTRUM_MGMT;
 
-		ieee80211_rx_bss_put(dev, bss);
+		ieee80211_rx_bss_put(local, bss);
 	} else {
 		rates = ~0;
 		rates_len = sband->n_bitrates;
@@ -992,7 +992,7 @@ static int ieee80211_privacy_mismatch(struct net_device *dev,
 	wep_privacy = !!ieee80211_sta_wep_configured(dev);
 	privacy_invoked = !!(ifsta->flags & IEEE80211_STA_PRIVACY_INVOKED);
 
-	ieee80211_rx_bss_put(dev, bss);
+	ieee80211_rx_bss_put(local, bss);
 
 	if ((bss_privacy == wep_privacy) || (bss_privacy == privacy_invoked))
 		return 0;
@@ -2094,7 +2094,7 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata,
 			sta->last_signal = bss->signal;
 			sta->last_qual = bss->qual;
 			sta->last_noise = bss->noise;
-			ieee80211_rx_bss_put(dev, bss);
+			ieee80211_rx_bss_put(local, bss);
 		}
 
 		err = sta_info_insert(sta);
@@ -2212,10 +2212,9 @@ static void __ieee80211_rx_bss_hash_add(struct net_device *dev,
 
 
 /* Caller must hold local->sta_bss_lock */
-static void __ieee80211_rx_bss_hash_del(struct net_device *dev,
+static void __ieee80211_rx_bss_hash_del(struct ieee80211_local *local,
 					struct ieee80211_sta_bss *bss)
 {
-	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
 	struct ieee80211_sta_bss *b, *prev = NULL;
 	b = local->sta_bss_hash[STA_HASH(bss->bssid)];
 	while (b) {
@@ -2367,39 +2366,35 @@ static void ieee80211_rx_bss_free(struct ieee80211_sta_bss *bss)
 }
 
 
-static void ieee80211_rx_bss_put(struct net_device *dev,
+static void ieee80211_rx_bss_put(struct ieee80211_local *local,
 				 struct ieee80211_sta_bss *bss)
 {
-	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
-
 	local_bh_disable();
 	if (!atomic_dec_and_lock(&bss->users, &local->sta_bss_lock)) {
 		local_bh_enable();
 		return;
 	}
 
-	__ieee80211_rx_bss_hash_del(dev, bss);
+	__ieee80211_rx_bss_hash_del(local, bss);
 	list_del(&bss->list);
 	spin_unlock_bh(&local->sta_bss_lock);
 	ieee80211_rx_bss_free(bss);
 }
 
 
-void ieee80211_rx_bss_list_init(struct net_device *dev)
+void ieee80211_rx_bss_list_init(struct ieee80211_local *local)
 {
-	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
 	spin_lock_init(&local->sta_bss_lock);
 	INIT_LIST_HEAD(&local->sta_bss_list);
 }
 
 
-void ieee80211_rx_bss_list_deinit(struct net_device *dev)
+void ieee80211_rx_bss_list_deinit(struct ieee80211_local *local)
 {
-	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
 	struct ieee80211_sta_bss *bss, *tmp;
 
 	list_for_each_entry_safe(bss, tmp, &local->sta_bss_list, list)
-		ieee80211_rx_bss_put(dev, bss);
+		ieee80211_rx_bss_put(local, bss);
 }
 
 
@@ -2411,8 +2406,6 @@ static int ieee80211_sta_join_ibss(struct net_device *dev,
 	int res, rates, i, j;
 	struct sk_buff *skb;
 	struct ieee80211_mgmt *mgmt;
-	struct ieee80211_tx_info *control;
-	struct rate_selection ratesel;
 	u8 *pos;
 	struct ieee80211_sub_if_data *sdata;
 	struct ieee80211_supported_band *sband;
@@ -2430,7 +2423,7 @@ static int ieee80211_sta_join_ibss(struct net_device *dev,
 		local->ops->reset_tsf(local_to_hw(local));
 	}
 	memcpy(ifsta->bssid, bss->bssid, ETH_ALEN);
-	res = ieee80211_if_config(dev);
+	res = ieee80211_if_config(sdata, IEEE80211_IFCC_BSSID);
 	if (res)
 		return res;
 
@@ -2444,19 +2437,16 @@ static int ieee80211_sta_join_ibss(struct net_device *dev,
 	if (res)
 		return res;
 
-	/* Set beacon template */
+	/* Build IBSS probe response */
 	skb = dev_alloc_skb(local->hw.extra_tx_headroom + 400);
-	do {
-		if (!skb)
-			break;
-
+	if (skb) {
 		skb_reserve(skb, local->hw.extra_tx_headroom);
 
 		mgmt = (struct ieee80211_mgmt *)
 			skb_put(skb, 24 + sizeof(mgmt->u.beacon));
 		memset(mgmt, 0, 24 + sizeof(mgmt->u.beacon));
 		mgmt->frame_control = IEEE80211_FC(IEEE80211_FTYPE_MGMT,
-						   IEEE80211_STYPE_BEACON);
+						   IEEE80211_STYPE_PROBE_RESP);
 		memset(mgmt->da, 0xff, ETH_ALEN);
 		memcpy(mgmt->sa, dev->dev_addr, ETH_ALEN);
 		memcpy(mgmt->bssid, ifsta->bssid, ETH_ALEN);
@@ -2500,61 +2490,22 @@ static int ieee80211_sta_join_ibss(struct net_device *dev,
 			memcpy(pos, &bss->supp_rates[8], rates);
 		}
 
-		control = IEEE80211_SKB_CB(skb);
-
-		rate_control_get_rate(dev, sband, skb, &ratesel);
-		if (ratesel.rate_idx < 0) {
-			printk(KERN_DEBUG "%s: Failed to determine TX rate "
-			       "for IBSS beacon\n", dev->name);
-			break;
-		}
-		control->control.vif = &sdata->vif;
-		control->tx_rate_idx = ratesel.rate_idx;
-		if (sdata->bss_conf.use_short_preamble &&
-		    sband->bitrates[ratesel.rate_idx].flags & IEEE80211_RATE_SHORT_PREAMBLE)
-			control->flags |= IEEE80211_TX_CTL_SHORT_PREAMBLE;
-		control->antenna_sel_tx = local->hw.conf.antenna_sel_tx;
-		control->flags |= IEEE80211_TX_CTL_NO_ACK;
-		control->flags |= IEEE80211_TX_CTL_DO_NOT_ENCRYPT;
-		control->control.retry_limit = 1;
-
-		ifsta->probe_resp = skb_copy(skb, GFP_ATOMIC);
-		if (ifsta->probe_resp) {
-			mgmt = (struct ieee80211_mgmt *)
-				ifsta->probe_resp->data;
-			mgmt->frame_control =
-				IEEE80211_FC(IEEE80211_FTYPE_MGMT,
-					     IEEE80211_STYPE_PROBE_RESP);
-		} else {
-			printk(KERN_DEBUG "%s: Could not allocate ProbeResp "
-			       "template for IBSS\n", dev->name);
-		}
+		ifsta->probe_resp = skb;
 
-		if (local->ops->beacon_update &&
-		    local->ops->beacon_update(local_to_hw(local), skb) == 0) {
-			printk(KERN_DEBUG "%s: Configured IBSS beacon "
-			       "template\n", dev->name);
-			skb = NULL;
-		}
-
-		rates = 0;
-		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 < sband->n_bitrates; j++)
-				if (sband->bitrates[j].bitrate == bitrate)
-					rates |= BIT(j);
-		}
-		ifsta->supp_rates_bits[local->hw.conf.channel->band] = rates;
-
-		ieee80211_sta_def_wmm_params(dev, bss, 1);
-	} while (0);
+		ieee80211_if_config(sdata, IEEE80211_IFCC_BEACON);
+	}
 
-	if (skb) {
-		printk(KERN_DEBUG "%s: Failed to configure IBSS beacon "
-		       "template\n", dev->name);
-		dev_kfree_skb(skb);
+	rates = 0;
+	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 < sband->n_bitrates; j++)
+			if (sband->bitrates[j].bitrate == bitrate)
+				rates |= BIT(j);
 	}
+	ifsta->supp_rates_bits[local->hw.conf.channel->band] = rates;
+
+	ieee80211_sta_def_wmm_params(dev, bss, 1);
 
 	ifsta->state = IEEE80211_IBSS_JOINED;
 	mod_timer(&ifsta->timer, jiffies + IEEE80211_IBSS_MERGE_INTERVAL);
@@ -2775,7 +2726,7 @@ static void ieee80211_rx_bss_info(struct net_device *dev,
 	 */
 	if (sdata->vif.type != IEEE80211_IF_TYPE_IBSS &&
 	    bss->probe_resp && beacon) {
-		ieee80211_rx_bss_put(dev, bss);
+		ieee80211_rx_bss_put(local, bss);
 		return;
 	}
 
@@ -2918,7 +2869,7 @@ static void ieee80211_rx_bss_info(struct net_device *dev,
 		}
 	}
 
-	ieee80211_rx_bss_put(dev, bss);
+	ieee80211_rx_bss_put(local, bss);
 }
 
 
@@ -3338,7 +3289,7 @@ static void ieee80211_mesh_housekeeping(struct net_device *dev,
 
 	free_plinks = mesh_plink_availables(sdata);
 	if (free_plinks != sdata->u.sta.accepting_plinks)
-		ieee80211_if_config_beacon(dev);
+		ieee80211_if_config(sdata, IEEE80211_IFCC_BEACON);
 
 	mod_timer(&ifsta->timer, jiffies +
 			IEEE80211_MESH_HOUSEKEEPING_INTERVAL);
@@ -3578,7 +3529,7 @@ static int ieee80211_sta_config_auth(struct net_device *dev,
 					       selected->ssid_len);
 		ieee80211_sta_set_bssid(dev, selected->bssid);
 		ieee80211_sta_def_wmm_params(dev, selected, 0);
-		ieee80211_rx_bss_put(dev, selected);
+		ieee80211_rx_bss_put(local, selected);
 		ifsta->state = IEEE80211_AUTHENTICATE;
 		ieee80211_sta_reset_auth(dev, ifsta);
 		return 0;
@@ -3655,7 +3606,7 @@ static int ieee80211_sta_create_ibss(struct net_device *dev,
 	}
 
 	ret = ieee80211_sta_join_ibss(dev, ifsta, bss);
-	ieee80211_rx_bss_put(dev, bss);
+	ieee80211_rx_bss_put(local, bss);
 	return ret;
 }
 
@@ -3711,7 +3662,7 @@ static int ieee80211_sta_find_ibss(struct net_device *dev,
 		       " based on configured SSID\n",
 		       dev->name, print_mac(mac, bssid));
 		ret = ieee80211_sta_join_ibss(dev, ifsta, bss);
-		ieee80211_rx_bss_put(dev, bss);
+		ieee80211_rx_bss_put(local, bss);
 		return ret;
 	}
 #ifdef CONFIG_MAC80211_IBSS_DEBUG
@@ -3762,28 +3713,45 @@ int ieee80211_sta_set_ssid(struct net_device *dev, char *ssid, size_t len)
 {
 	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
 	struct ieee80211_if_sta *ifsta;
+	int res;
 
 	if (len > IEEE80211_MAX_SSID_LEN)
 		return -EINVAL;
 
 	ifsta = &sdata->u.sta;
 
-	if (ifsta->ssid_len != len || memcmp(ifsta->ssid, ssid, len) != 0)
+	if (ifsta->ssid_len != len || memcmp(ifsta->ssid, ssid, len) != 0) {
+		memset(ifsta->ssid, 0, sizeof(ifsta->ssid));
+		memcpy(ifsta->ssid, ssid, len);
+		ifsta->ssid_len = len;
 		ifsta->flags &= ~IEEE80211_STA_PREV_BSSID_SET;
-	memcpy(ifsta->ssid, ssid, len);
-	memset(ifsta->ssid + len, 0, IEEE80211_MAX_SSID_LEN - len);
-	ifsta->ssid_len = len;
+
+		res = 0;
+		/*
+		 * Hack! MLME code needs to be cleaned up to have different
+		 * entry points for configuration and internal selection change
+		 */
+		if (netif_running(sdata->dev))
+			res = ieee80211_if_config(sdata, IEEE80211_IFCC_SSID);
+		if (res) {
+			printk(KERN_DEBUG "%s: Failed to config new SSID to "
+			       "the low-level driver\n", dev->name);
+			return res;
+		}
+	}
 
 	if (len)
 		ifsta->flags |= IEEE80211_STA_SSID_SET;
 	else
 		ifsta->flags &= ~IEEE80211_STA_SSID_SET;
+
 	if (sdata->vif.type == IEEE80211_IF_TYPE_IBSS &&
 	    !(ifsta->flags & IEEE80211_STA_BSSID_SET)) {
 		ifsta->ibss_join_req = jiffies;
 		ifsta->state = IEEE80211_IBSS_SEARCH;
 		return ieee80211_sta_find_ibss(dev, ifsta);
 	}
+
 	return 0;
 }
 
@@ -3809,7 +3777,12 @@ int ieee80211_sta_set_bssid(struct net_device *dev, u8 *bssid)
 
 	if (memcmp(ifsta->bssid, bssid, ETH_ALEN) != 0) {
 		memcpy(ifsta->bssid, bssid, ETH_ALEN);
-		res = ieee80211_if_config(dev);
+		res = 0;
+		/*
+		 * Hack! See also ieee80211_sta_set_ssid.
+		 */
+		if (netif_running(sdata->dev))
+			res = ieee80211_if_config(sdata, IEEE80211_IFCC_BSSID);
 		if (res) {
 			printk(KERN_DEBUG "%s: Failed to config new BSSID to "
 			       "the low-level driver\n", dev->name);
@@ -3907,11 +3880,6 @@ void ieee80211_scan_completed(struct ieee80211_hw *hw)
 
 	rcu_read_lock();
 	list_for_each_entry_rcu(sdata, &local->interfaces, list) {
-
-		/* No need to wake the master device. */
-		if (sdata->dev == local->mdev)
-			continue;
-
 		/* Tell AP we're back */
 		if (sdata->vif.type == IEEE80211_IF_TYPE_STA &&
 		    sdata->u.sta.flags & IEEE80211_STA_ASSOCIATED)
@@ -4077,12 +4045,6 @@ static int ieee80211_sta_start_scan(struct net_device *dev,
 
 	rcu_read_lock();
 	list_for_each_entry_rcu(sdata, &local->interfaces, list) {
-
-		/* Don't stop the master interface, otherwise we can't transmit
-		 * probes! */
-		if (sdata->dev == local->mdev)
-			continue;
-
 		netif_stop_queue(sdata->dev);
 		if (sdata->vif.type == IEEE80211_IF_TYPE_STA &&
 		    (sdata->u.sta.flags & IEEE80211_STA_ASSOCIATED))
@@ -4398,7 +4360,7 @@ struct sta_info *ieee80211_ibss_add_sta(struct net_device *dev,
 		return NULL;
 	}
 
-	if (!ieee80211_bssid_match(bssid, sdata->u.sta.bssid))
+	if (compare_ether_addr(bssid, sdata->u.sta.bssid))
 		return NULL;
 
 #ifdef CONFIG_MAC80211_VERBOSE_DEBUG
@@ -4473,12 +4435,10 @@ void ieee80211_notify_mac(struct ieee80211_hw *hw,
 	case IEEE80211_NOTIFY_RE_ASSOC:
 		rcu_read_lock();
 		list_for_each_entry_rcu(sdata, &local->interfaces, list) {
+			if (sdata->vif.type != IEEE80211_IF_TYPE_STA)
+				continue;
 
-			if (sdata->vif.type == IEEE80211_IF_TYPE_STA) {
-				ieee80211_sta_req_auth(sdata->dev,
-						       &sdata->u.sta);
-			}
-
+			ieee80211_sta_req_auth(sdata->dev, &sdata->u.sta);
 		}
 		rcu_read_unlock();
 		break;
diff --git a/net/mac80211/rc80211_pid_algo.c b/net/mac80211/rc80211_pid_algo.c
index 742c5b06cffd..a914ba73ccf5 100644
--- a/net/mac80211/rc80211_pid_algo.c
+++ b/net/mac80211/rc80211_pid_algo.c
@@ -259,8 +259,8 @@ static void rate_control_pid_tx_status(void *priv, struct net_device *dev,
 
 	/* Don't update the state if we're not controlling the rate. */
 	sdata = sta->sdata;
-	if (sdata->bss && sdata->bss->force_unicast_rateidx > -1) {
-		sta->txrate_idx = sdata->bss->max_ratectrl_rateidx;
+	if (sdata->force_unicast_rateidx > -1) {
+		sta->txrate_idx = sdata->max_ratectrl_rateidx;
 		goto unlock;
 	}
 
@@ -337,8 +337,8 @@ static void rate_control_pid_get_rate(void *priv, struct net_device *dev,
 
 	/* 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;
+	if (sdata->force_unicast_rateidx > -1)
+		sta->txrate_idx = sdata->force_unicast_rateidx;
 
 	rateidx = sta->txrate_idx;
 
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
index fab443d717eb..6d9ae67c27ca 100644
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
@@ -334,13 +334,18 @@ static void ieee80211_parse_qos(struct ieee80211_rx_data *rx)
 		else
 			rx->flags &= ~IEEE80211_RX_AMSDU;
 	} else {
-		if (unlikely(ieee80211_is_mgmt(hdr->frame_control))) {
-			/* Separate TID for management frames */
-			tid = NUM_RX_DATA_QUEUES - 1;
-		} else {
-			/* no qos control present */
-			tid = 0; /* 802.1d - Best Effort */
-		}
+		/*
+		 * IEEE 802.11-2007, 7.1.3.4.1 ("Sequence Number field"):
+		 *
+		 *	Sequence numbers for management frames, QoS data
+		 *	frames with a broadcast/multicast address in the
+		 *	Address 1 field, and all non-QoS data frames sent
+		 *	by QoS STAs are assigned using an additional single
+		 *	modulo-4096 counter, [...]
+		 *
+		 * We also use that counter for non-QoS STAs.
+		 */
+		tid = NUM_RX_DATA_QUEUES - 1;
 	}
 
 	rx->queue = tid;
@@ -647,8 +652,7 @@ static void ap_sta_ps_start(struct net_device *dev, struct sta_info *sta)
 
 	sdata = sta->sdata;
 
-	if (sdata->bss)
-		atomic_inc(&sdata->bss->num_sta_ps);
+	atomic_inc(&sdata->bss->num_sta_ps);
 	set_and_clear_sta_flags(sta, WLAN_STA_PS, WLAN_STA_PSPOLL);
 #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
 	printk(KERN_DEBUG "%s: STA %s aid %d enters power save mode\n",
@@ -667,8 +671,7 @@ static int ap_sta_ps_end(struct net_device *dev, struct sta_info *sta)
 
 	sdata = sta->sdata;
 
-	if (sdata->bss)
-		atomic_dec(&sdata->bss->num_sta_ps);
+	atomic_dec(&sdata->bss->num_sta_ps);
 
 	clear_sta_flags(sta, WLAN_STA_PS | WLAN_STA_PSPOLL);
 
@@ -742,7 +745,9 @@ ieee80211_rx_h_sta_process(struct ieee80211_rx_data *rx)
 	sta->last_qual = rx->status->qual;
 	sta->last_noise = rx->status->noise;
 
-	if (!ieee80211_has_morefrags(hdr->frame_control)) {
+	if (!ieee80211_has_morefrags(hdr->frame_control) &&
+	    (rx->sdata->vif.type == IEEE80211_IF_TYPE_AP ||
+	     rx->sdata->vif.type == IEEE80211_IF_TYPE_VLAN)) {
 		/* Change STA power saving mode only in the end of a frame
 		 * exchange sequence */
 		if (test_sta_flags(sta, WLAN_STA_PS) &&
@@ -1772,11 +1777,6 @@ static int prepare_for_handlers(struct ieee80211_sub_if_data *sdata,
 				return 0;
 			rx->flags &= ~IEEE80211_RX_RA_MATCH;
 		}
-		if (sdata->dev == sdata->local->mdev &&
-		    !(rx->flags & IEEE80211_RX_IN_SCAN))
-			/* do not receive anything via
-			 * master device when not scanning */
-			return 0;
 		break;
 	case IEEE80211_IF_TYPE_WDS:
 		if (bssid || !ieee80211_is_data(hdr->frame_control))
@@ -2046,8 +2046,8 @@ static u8 ieee80211_rx_reorder_ampdu(struct ieee80211_local *local,
 
 	tid_agg_rx = sta->ampdu_mlme.tid_rx[tid];
 
-	/* null data frames are excluded */
-	if (unlikely(ieee80211_is_nullfunc(hdr->frame_control)))
+	/* qos null data frames are excluded */
+	if (unlikely(hdr->frame_control & cpu_to_le16(IEEE80211_STYPE_NULLFUNC)))
 		goto end_reorder;
 
 	/* new un-ordered ampdu frame - process it */
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c
index 47d2c1bbfcaa..f2ba653b9d69 100644
--- a/net/mac80211/sta_info.c
+++ b/net/mac80211/sta_info.c
@@ -320,7 +320,9 @@ int sta_info_insert(struct sta_info *sta)
 	/* notify driver */
 	if (local->ops->sta_notify) {
 		if (sdata->vif.type == IEEE80211_IF_TYPE_VLAN)
-			sdata = sdata->u.vlan.ap;
+			sdata = container_of(sdata->bss,
+					     struct ieee80211_sub_if_data,
+					     u.ap);
 
 		local->ops->sta_notify(local_to_hw(local), &sdata->vif,
 				       STA_NOTIFY_ADD, sta->addr);
@@ -375,8 +377,10 @@ static inline void __bss_tim_clear(struct ieee80211_if_ap *bss, u16 aid)
 static void __sta_info_set_tim_bit(struct ieee80211_if_ap *bss,
 				   struct sta_info *sta)
 {
-	if (bss)
-		__bss_tim_set(bss, sta->aid);
+	BUG_ON(!bss);
+
+	__bss_tim_set(bss, sta->aid);
+
 	if (sta->local->ops->set_tim) {
 		sta->local->tim_in_locked_section = true;
 		sta->local->ops->set_tim(local_to_hw(sta->local), sta->aid, 1);
@@ -388,6 +392,8 @@ void sta_info_set_tim_bit(struct sta_info *sta)
 {
 	unsigned long flags;
 
+	BUG_ON(!sta->sdata->bss);
+
 	spin_lock_irqsave(&sta->local->sta_lock, flags);
 	__sta_info_set_tim_bit(sta->sdata->bss, sta);
 	spin_unlock_irqrestore(&sta->local->sta_lock, flags);
@@ -396,8 +402,10 @@ void sta_info_set_tim_bit(struct sta_info *sta)
 static void __sta_info_clear_tim_bit(struct ieee80211_if_ap *bss,
 				     struct sta_info *sta)
 {
-	if (bss)
-		__bss_tim_clear(bss, sta->aid);
+	BUG_ON(!bss);
+
+	__bss_tim_clear(bss, sta->aid);
+
 	if (sta->local->ops->set_tim) {
 		sta->local->tim_in_locked_section = true;
 		sta->local->ops->set_tim(local_to_hw(sta->local), sta->aid, 0);
@@ -409,6 +417,8 @@ void sta_info_clear_tim_bit(struct sta_info *sta)
 {
 	unsigned long flags;
 
+	BUG_ON(!sta->sdata->bss);
+
 	spin_lock_irqsave(&sta->local->sta_lock, flags);
 	__sta_info_clear_tim_bit(sta->sdata->bss, sta);
 	spin_unlock_irqrestore(&sta->local->sta_lock, flags);
@@ -437,8 +447,9 @@ void __sta_info_unlink(struct sta_info **sta)
 	list_del(&(*sta)->list);
 
 	if (test_and_clear_sta_flags(*sta, WLAN_STA_PS)) {
-		if (sdata->bss)
-			atomic_dec(&sdata->bss->num_sta_ps);
+		BUG_ON(!sdata->bss);
+
+		atomic_dec(&sdata->bss->num_sta_ps);
 		__sta_info_clear_tim_bit(sdata->bss, *sta);
 	}
 
@@ -446,7 +457,9 @@ void __sta_info_unlink(struct sta_info **sta)
 
 	if (local->ops->sta_notify) {
 		if (sdata->vif.type == IEEE80211_IF_TYPE_VLAN)
-			sdata = sdata->u.vlan.ap;
+			sdata = container_of(sdata->bss,
+					     struct ieee80211_sub_if_data,
+					     u.ap);
 
 		local->ops->sta_notify(local_to_hw(local), &sdata->vif,
 				       STA_NOTIFY_REMOVE, (*sta)->addr);
diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h
index 94311dcfe043..109db787ccb7 100644
--- a/net/mac80211/sta_info.h
+++ b/net/mac80211/sta_info.h
@@ -285,6 +285,7 @@ struct sta_info {
 	unsigned long tx_fragments;
 	int txrate_idx;
 	int last_txrate_idx;
+	u16 tid_seq[IEEE80211_QOS_CTL_TID_MASK + 1];
 #ifdef CONFIG_MAC80211_DEBUG_COUNTERS
 	unsigned int wme_tx_queue[NUM_RX_DATA_QUEUES];
 #endif
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
index 9bd9faac3c3c..0fbadd8b983c 100644
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -38,16 +38,6 @@
 
 /* misc utils */
 
-static inline void ieee80211_include_sequence(struct ieee80211_sub_if_data *sdata,
-					      struct ieee80211_hdr *hdr)
-{
-	/* Set the sequence number for this frame. */
-	hdr->seq_ctrl = cpu_to_le16(sdata->sequence);
-
-	/* Increase the sequence number. */
-	sdata->sequence = (sdata->sequence + 0x10) & IEEE80211_SCTL_SEQ;
-}
-
 #ifdef CONFIG_MAC80211_LOWTX_FRAME_DUMP
 static void ieee80211_dump_frame(const char *ifname, const char *title,
 				 const struct sk_buff *skb)
@@ -274,17 +264,6 @@ ieee80211_tx_h_check_assoc(struct ieee80211_tx_data *tx)
 	return TX_CONTINUE;
 }
 
-static ieee80211_tx_result debug_noinline
-ieee80211_tx_h_sequence(struct ieee80211_tx_data *tx)
-{
-	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)tx->skb->data;
-
-	if (ieee80211_hdrlen(hdr->frame_control) >= 24)
-		ieee80211_include_sequence(tx->sdata, hdr);
-
-	return TX_CONTINUE;
-}
-
 /* This function is called whenever the AP is about to exceed the maximum limit
  * of buffered frames for power saving STAs. This situation should not really
  * happen often during normal operation, so dropping the oldest buffered packet
@@ -303,8 +282,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->vif.type != IEEE80211_IF_TYPE_AP)
+		if (sdata->vif.type != IEEE80211_IF_TYPE_AP)
 			continue;
 		ap = &sdata->u.ap;
 		skb = skb_dequeue(&ap->ps_bc_buf);
@@ -346,8 +324,12 @@ ieee80211_tx_h_multicast_ps_buf(struct ieee80211_tx_data *tx)
 	 * This is done either by the hardware or us.
 	 */
 
-	/* not AP/IBSS or ordered frame */
-	if (!tx->sdata->bss || (tx->fc & IEEE80211_FCTL_ORDER))
+	/* powersaving STAs only in AP/VLAN mode */
+	if (!tx->sdata->bss)
+		return TX_CONTINUE;
+
+	/* no buffering for ordered frames */
+	if (tx->fc & IEEE80211_FCTL_ORDER)
 		return TX_CONTINUE;
 
 	/* no stations in PS mode */
@@ -639,6 +621,49 @@ ieee80211_tx_h_misc(struct ieee80211_tx_data *tx)
 }
 
 static ieee80211_tx_result debug_noinline
+ieee80211_tx_h_sequence(struct ieee80211_tx_data *tx)
+{
+	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx->skb);
+	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)tx->skb->data;
+	u16 *seq;
+	u8 *qc;
+	int tid;
+
+	/* only for injected frames */
+	if (unlikely(ieee80211_is_ctl(hdr->frame_control)))
+		return TX_CONTINUE;
+
+	if (ieee80211_hdrlen(hdr->frame_control) < 24)
+		return TX_CONTINUE;
+
+	if (!ieee80211_is_data_qos(hdr->frame_control)) {
+		info->flags |= IEEE80211_TX_CTL_ASSIGN_SEQ;
+		return TX_CONTINUE;
+	}
+
+	/*
+	 * This should be true for injected/management frames only, for
+	 * management frames we have set the IEEE80211_TX_CTL_ASSIGN_SEQ
+	 * above since they are not QoS-data frames.
+	 */
+	if (!tx->sta)
+		return TX_CONTINUE;
+
+	/* include per-STA, per-TID sequence counter */
+
+	qc = ieee80211_get_qos_ctl(hdr);
+	tid = *qc & IEEE80211_QOS_CTL_TID_MASK;
+	seq = &tx->sta->tid_seq[tid];
+
+	hdr->seq_ctrl = cpu_to_le16(*seq);
+
+	/* Increase the sequence number. */
+	*seq = (*seq + 0x10) & IEEE80211_SCTL_SEQ;
+
+	return TX_CONTINUE;
+}
+
+static ieee80211_tx_result debug_noinline
 ieee80211_tx_h_fragment(struct ieee80211_tx_data *tx)
 {
 	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)tx->skb->data;
@@ -1107,12 +1132,12 @@ static int invoke_tx_handlers(struct ieee80211_tx_data *tx)
 		goto txh_done;
 
 	CALL_TXH(ieee80211_tx_h_check_assoc)
-	CALL_TXH(ieee80211_tx_h_sequence)
 	CALL_TXH(ieee80211_tx_h_ps_buf)
 	CALL_TXH(ieee80211_tx_h_select_key)
 	CALL_TXH(ieee80211_tx_h_michael_mic_add)
 	CALL_TXH(ieee80211_tx_h_rate_ctrl)
 	CALL_TXH(ieee80211_tx_h_misc)
+	CALL_TXH(ieee80211_tx_h_sequence)
 	CALL_TXH(ieee80211_tx_h_fragment)
 	/* handlers after fragment must be aware of tx info fragmentation! */
 	CALL_TXH(ieee80211_tx_h_encrypt)
@@ -1785,17 +1810,17 @@ struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw,
 				     struct ieee80211_vif *vif)
 {
 	struct ieee80211_local *local = hw_to_local(hw);
-	struct sk_buff *skb;
+	struct sk_buff *skb = NULL;
 	struct ieee80211_tx_info *info;
 	struct net_device *bdev;
 	struct ieee80211_sub_if_data *sdata = NULL;
 	struct ieee80211_if_ap *ap = NULL;
+	struct ieee80211_if_sta *ifsta = NULL;
 	struct rate_selection rsel;
 	struct beacon_data *beacon;
 	struct ieee80211_supported_band *sband;
 	struct ieee80211_mgmt *mgmt;
 	int *num_beacons;
-	bool err = true;
 	enum ieee80211_band band = local->hw.conf.channel->band;
 	u8 *pos;
 
@@ -1824,9 +1849,6 @@ struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw,
 			memcpy(skb_put(skb, beacon->head_len), beacon->head,
 			       beacon->head_len);
 
-			ieee80211_include_sequence(sdata,
-					(struct ieee80211_hdr *)skb->data);
-
 			/*
 			 * Not very nice, but we want to allow the driver to call
 			 * ieee80211_beacon_get() as a response to the set_tim()
@@ -1849,9 +1871,24 @@ struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw,
 				       beacon->tail, beacon->tail_len);
 
 			num_beacons = &ap->num_beacons;
+		} else
+			goto out;
+	} else if (sdata->vif.type == IEEE80211_IF_TYPE_IBSS) {
+		struct ieee80211_hdr *hdr;
+		ifsta = &sdata->u.sta;
 
-			err = false;
-		}
+		if (!ifsta->probe_resp)
+			goto out;
+
+		skb = skb_copy(ifsta->probe_resp, GFP_ATOMIC);
+		if (!skb)
+			goto out;
+
+		hdr = (struct ieee80211_hdr *) skb->data;
+		hdr->frame_control = IEEE80211_FC(IEEE80211_FTYPE_MGMT,
+						  IEEE80211_STYPE_BEACON);
+
+		num_beacons = &ifsta->num_beacons;
 	} else if (ieee80211_vif_is_mesh(&sdata->vif)) {
 		/* headroom, head length, tail length and maximum TIM length */
 		skb = dev_alloc_skb(local->tx_headroom + 400);
@@ -1878,17 +1915,8 @@ struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw,
 		mesh_mgmt_ies_add(skb, sdata->dev);
 
 		num_beacons = &sdata->u.sta.num_beacons;
-
-		err = false;
-	}
-
-	if (err) {
-#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
-		if (net_ratelimit())
-			printk(KERN_DEBUG "no beacon data avail for %s\n",
-			       bdev->name);
-#endif /* CONFIG_MAC80211_VERBOSE_DEBUG */
-		skb = NULL;
+	} else {
+		WARN_ON(1);
 		goto out;
 	}
 
@@ -1910,14 +1938,18 @@ struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw,
 
 	info->control.vif = vif;
 	info->tx_rate_idx = rsel.rate_idx;
+
+	info->flags |= IEEE80211_TX_CTL_NO_ACK;
+	info->flags |= IEEE80211_TX_CTL_DO_NOT_ENCRYPT;
+	info->flags |= IEEE80211_TX_CTL_CLEAR_PS_FILT;
+	info->flags |= IEEE80211_TX_CTL_ASSIGN_SEQ;
 	if (sdata->bss_conf.use_short_preamble &&
 	    sband->bitrates[rsel.rate_idx].flags & IEEE80211_RATE_SHORT_PREAMBLE)
 		info->flags |= IEEE80211_TX_CTL_SHORT_PREAMBLE;
+
 	info->antenna_sel_tx = local->hw.conf.antenna_sel_tx;
-	info->flags |= IEEE80211_TX_CTL_NO_ACK;
-	info->flags |= IEEE80211_TX_CTL_DO_NOT_ENCRYPT;
 	info->control.retry_limit = 1;
-	info->flags |= IEEE80211_TX_CTL_CLEAR_PS_FILT;
+
 	(*num_beacons)++;
 out:
 	rcu_read_unlock();
diff --git a/net/mac80211/util.c b/net/mac80211/util.c
index ce62b163b82c..89ce4e07bd84 100644
--- a/net/mac80211/util.c
+++ b/net/mac80211/util.c
@@ -428,8 +428,6 @@ void ieee80211_iterate_active_interfaces(
 		case IEEE80211_IF_TYPE_MESH_POINT:
 			break;
 		}
-		if (sdata->dev == local->mdev)
-			continue;
 		if (netif_running(sdata->dev))
 			iterator(data, sdata->dev->dev_addr,
 				 &sdata->vif);
@@ -463,8 +461,6 @@ void ieee80211_iterate_active_interfaces_atomic(
 		case IEEE80211_IF_TYPE_MESH_POINT:
 			break;
 		}
-		if (sdata->dev == local->mdev)
-			continue;
 		if (netif_running(sdata->dev))
 			iterator(data, sdata->dev->dev_addr,
 				 &sdata->vif);
diff --git a/net/mac80211/wext.c b/net/mac80211/wext.c
index 736c32e340f2..34fa8ed1e784 100644
--- a/net/mac80211/wext.c
+++ b/net/mac80211/wext.c
@@ -296,15 +296,7 @@ static int ieee80211_ioctl_siwmode(struct net_device *dev,
 		return -EINVAL;
 	}
 
-	if (type == sdata->vif.type)
-		return 0;
-	if (netif_running(dev))
-		return -EBUSY;
-
-	ieee80211_if_reinit(dev);
-	ieee80211_if_set_type(dev, type);
-
-	return 0;
+	return ieee80211_if_change_type(sdata, type);
 }
 
 
@@ -452,7 +444,7 @@ static int ieee80211_ioctl_siwessid(struct net_device *dev,
 		memset(sdata->u.ap.ssid + len, 0,
 		       IEEE80211_MAX_SSID_LEN - len);
 		sdata->u.ap.ssid_len = len;
-		return ieee80211_if_config(dev);
+		return ieee80211_if_config(sdata, IEEE80211_IFCC_SSID);
 	}
 	return -EOPNOTSUPP;
 }
@@ -627,16 +619,14 @@ static int ieee80211_ioctl_siwrate(struct net_device *dev,
 	struct ieee80211_supported_band *sband;
 
 	sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-	if (!sdata->bss)
-		return -ENODEV;
 
 	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 */
-	sdata->bss->max_ratectrl_rateidx = -1;
-	sdata->bss->force_unicast_rateidx = -1;
+	sdata->max_ratectrl_rateidx = -1;
+	sdata->force_unicast_rateidx = -1;
 	if (rate->value < 0)
 		return 0;
 
@@ -645,9 +635,9 @@ static int ieee80211_ioctl_siwrate(struct net_device *dev,
 		int this_rate = brate->bitrate;
 
 		if (target_rate == this_rate) {
-			sdata->bss->max_ratectrl_rateidx = i;
+			sdata->max_ratectrl_rateidx = i;
 			if (rate->fixed)
-				sdata->bss->force_unicast_rateidx = i;
+				sdata->force_unicast_rateidx = i;
 			err = 0;
 			break;
 		}
@@ -1009,6 +999,45 @@ static int ieee80211_ioctl_giwencode(struct net_device *dev,
 	return 0;
 }
 
+static int ieee80211_ioctl_siwpower(struct net_device *dev,
+				    struct iw_request_info *info,
+				    struct iw_param *wrq,
+				    char *extra)
+{
+	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+	struct ieee80211_conf *conf = &local->hw.conf;
+
+	if (wrq->disabled) {
+		conf->flags &= ~IEEE80211_CONF_PS;
+		return ieee80211_hw_config(local);
+	}
+
+	switch (wrq->flags & IW_POWER_MODE) {
+	case IW_POWER_ON:       /* If not specified */
+	case IW_POWER_MODE:     /* If set all mask */
+	case IW_POWER_ALL_R:    /* If explicitely state all */
+		conf->flags |= IEEE80211_CONF_PS;
+		break;
+	default:                /* Otherwise we don't support it */
+		return -EINVAL;
+	}
+
+	return ieee80211_hw_config(local);
+}
+
+static int ieee80211_ioctl_giwpower(struct net_device *dev,
+				    struct iw_request_info *info,
+				    union iwreq_data *wrqu,
+				    char *extra)
+{
+	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+	struct ieee80211_conf *conf = &local->hw.conf;
+
+	wrqu->power.disabled = !(conf->flags & IEEE80211_CONF_PS);
+
+	return 0;
+}
+
 static int ieee80211_ioctl_siwauth(struct net_device *dev,
 				   struct iw_request_info *info,
 				   struct iw_param *data, char *extra)
@@ -1211,8 +1240,8 @@ static const iw_handler ieee80211_handler[] =
 	(iw_handler) ieee80211_ioctl_giwretry,		/* SIOCGIWRETRY */
 	(iw_handler) ieee80211_ioctl_siwencode,		/* SIOCSIWENCODE */
 	(iw_handler) ieee80211_ioctl_giwencode,		/* SIOCGIWENCODE */
-	(iw_handler) NULL,				/* SIOCSIWPOWER */
-	(iw_handler) NULL,				/* SIOCGIWPOWER */
+	(iw_handler) ieee80211_ioctl_siwpower,		/* SIOCSIWPOWER */
+	(iw_handler) ieee80211_ioctl_giwpower,		/* SIOCGIWPOWER */
 	(iw_handler) NULL,				/* -- hole -- */
 	(iw_handler) NULL,				/* -- hole -- */
 	(iw_handler) ieee80211_ioctl_siwgenie,		/* SIOCSIWGENIE */
diff --git a/net/wireless/Kconfig b/net/wireless/Kconfig
index 79270903bda6..ab015c62d561 100644
--- a/net/wireless/Kconfig
+++ b/net/wireless/Kconfig
@@ -29,3 +29,14 @@ config WIRELESS_EXT
 
 	  Say N (if you can) unless you know you need wireless
 	  extensions for external modules.
+
+config WIRELESS_EXT_SYSFS
+	bool "Wireless extensions sysfs files"
+	default y
+	depends on WIRELESS_EXT && SYSFS
+	help
+	  This option enables the deprecated wireless statistics
+	  files in /sys/class/net/*/wireless/. The same information
+	  is available via the ioctls as well.
+
+	  Say Y if you have programs using it (we don't know of any).