Browse Source

Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-next-2.6

David S. Miller 17 years ago
parent
commit
fc943b12e4
62 changed files with 1458 additions and 1724 deletions
  1. 10 0
      Documentation/feature-removal-schedule.txt
  2. 12 1
      drivers/net/wireless/ath5k/base.c
  3. 20 28
      drivers/net/wireless/b43/main.c
  4. 2 1
      drivers/net/wireless/b43/xmit.c
  5. 17 28
      drivers/net/wireless/b43legacy/main.c
  6. 1 2
      drivers/net/wireless/b43legacy/xmit.c
  7. 62 84
      drivers/net/wireless/iwlwifi/iwl-3945-led.c
  8. 1 1
      drivers/net/wireless/iwlwifi/iwl-3945-led.h
  9. 25 25
      drivers/net/wireless/iwlwifi/iwl-3945.c
  10. 1 19
      drivers/net/wireless/iwlwifi/iwl-3945.h
  11. 1 0
      drivers/net/wireless/iwlwifi/iwl-4965-hw.h
  12. 0 2
      drivers/net/wireless/iwlwifi/iwl-4965-rs.c
  13. 36 6
      drivers/net/wireless/iwlwifi/iwl-4965.c
  14. 1 0
      drivers/net/wireless/iwlwifi/iwl-5000-hw.h
  15. 42 6
      drivers/net/wireless/iwlwifi/iwl-5000.c
  16. 20 10
      drivers/net/wireless/iwlwifi/iwl-commands.h
  17. 1 1
      drivers/net/wireless/iwlwifi/iwl-core.c
  18. 4 1
      drivers/net/wireless/iwlwifi/iwl-core.h
  19. 10 17
      drivers/net/wireless/iwlwifi/iwl-dev.h
  20. 94 113
      drivers/net/wireless/iwlwifi/iwl-led.c
  21. 2 3
      drivers/net/wireless/iwlwifi/iwl-led.h
  22. 17 20
      drivers/net/wireless/iwlwifi/iwl-rx.c
  23. 55 48
      drivers/net/wireless/iwlwifi/iwl-scan.c
  24. 1 7
      drivers/net/wireless/iwlwifi/iwl-tx.c
  25. 16 129
      drivers/net/wireless/iwlwifi/iwl3945-base.c
  26. 52 56
      drivers/net/wireless/iwlwifi/iwl4965-base.c
  27. 1 1
      drivers/net/wireless/mac80211_hwsim.c
  28. 35 54
      drivers/net/wireless/rt2x00/rt2400pci.c
  29. 35 55
      drivers/net/wireless/rt2x00/rt2500pci.c
  30. 60 94
      drivers/net/wireless/rt2x00/rt2500usb.c
  31. 4 33
      drivers/net/wireless/rt2x00/rt2x00.h
  32. 2 0
      drivers/net/wireless/rt2x00/rt2x00config.c
  33. 2 7
      drivers/net/wireless/rt2x00/rt2x00dev.c
  34. 8 0
      drivers/net/wireless/rt2x00/rt2x00firmware.c
  35. 8 0
      drivers/net/wireless/rt2x00/rt2x00lib.h
  36. 26 14
      drivers/net/wireless/rt2x00/rt2x00mac.c
  37. 61 6
      drivers/net/wireless/rt2x00/rt2x00queue.c
  38. 36 67
      drivers/net/wireless/rt2x00/rt61pci.c
  39. 44 71
      drivers/net/wireless/rt2x00/rt73usb.c
  40. 15 8
      drivers/net/wireless/rtl8187_dev.c
  41. 17 4
      drivers/net/wireless/rtl8187_rtl8225.c
  42. 11 4
      drivers/net/wireless/rtl8187_rtl8225.h
  43. 7 15
      drivers/net/wireless/zd1211rw/zd_mac.c
  44. 1 0
      include/linux/ssb/ssb.h
  45. 35 38
      include/net/mac80211.h
  46. 2 2
      net/core/net-sysfs.c
  47. 10 26
      net/mac80211/cfg.c
  48. 1 14
      net/mac80211/debugfs.c
  49. 31 17
      net/mac80211/debugfs_netdev.c
  50. 0 5
      net/mac80211/debugfs_netdev.h
  51. 31 36
      net/mac80211/ieee80211_i.h
  52. 169 223
      net/mac80211/iface.c
  53. 55 116
      net/mac80211/main.c
  54. 66 106
      net/mac80211/mlme.c
  55. 4 4
      net/mac80211/rc80211_pid_algo.c
  56. 19 19
      net/mac80211/rx.c
  57. 21 8
      net/mac80211/sta_info.c
  58. 1 0
      net/mac80211/sta_info.h
  59. 79 47
      net/mac80211/tx.c
  60. 0 4
      net/mac80211/util.c
  61. 47 18
      net/mac80211/wext.c
  62. 11 0
      net/wireless/Kconfig

+ 10 - 0
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
 	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.
 	removal fixed lm-sensors (2.x or 3.x) should be readily available.
 Who:	Rene Herman <rene.herman@gmail.com>
 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>

+ 12 - 1
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_tx_stats 	= ath5k_get_tx_stats,
 	.get_tsf 	= ath5k_get_tsf,
 	.get_tsf 	= ath5k_get_tsf,
 	.reset_tsf 	= ath5k_reset_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. */
 		 * a clean way of letting us retrieve this yet. */
 		ath5k_hw_set_associd(ah, ah->ah_bssid, 0);
 		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);
 	mutex_unlock(&sc->lock);
 
 
 	return ath5k_reset(hw);
 	return ath5k_reset(hw);

+ 20 - 28
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.
 /* Asynchronously update the packet templates in template RAM.
  * Locking: Requires wl->irq_lock to be locked. */
  * 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.
 	/* This is the top half of the ansynchronous beacon update.
 	 * The bottom half is the beacon IRQ.
 	 * The bottom half is the beacon IRQ.
 	 * Beacon update must be asynchronous to avoid sending an
 	 * Beacon update must be asynchronous to avoid sending an
 	 * invalid beacon. This can happen for example, if the firmware
 	 * invalid beacon. This can happen for example, if the firmware
 	 * transmits a beacon while we are updating it. */
 	 * 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)
 	if (wl->current_beacon)
 		dev_kfree_skb_any(wl->current_beacon);
 		dev_kfree_skb_any(wl->current_beacon);
 	wl->current_beacon = 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_status(dev) >= B43_STAT_INITIALIZED) {
 		if (b43_is_mode(wl, IEEE80211_IF_TYPE_AP) ||
 		if (b43_is_mode(wl, IEEE80211_IF_TYPE_AP) ||
 		    b43_is_mode(wl, IEEE80211_IF_TYPE_MESH_POINT)) {
 		    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);
 		b43_write_mac_bssid_templates(dev);
 	}
 	}
@@ -4334,33 +4348,12 @@ out_unlock:
 }
 }
 
 
 static int b43_op_beacon_set_tim(struct ieee80211_hw *hw, int aid, int set)
 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);
 	struct b43_wl *wl = hw_to_b43_wl(hw);
 	unsigned long flags;
 	unsigned long flags;
 
 
 	spin_lock_irqsave(&wl->irq_lock, flags);
 	spin_lock_irqsave(&wl->irq_lock, flags);
-	b43_update_templates(wl, beacon);
+	b43_update_templates(wl);
 	spin_unlock_irqrestore(&wl->irq_lock, flags);
 	spin_unlock_irqrestore(&wl->irq_lock, flags);
 
 
 	return 0;
 	return 0;
@@ -4391,7 +4384,6 @@ static const struct ieee80211_ops b43_hw_ops = {
 	.stop			= b43_op_stop,
 	.stop			= b43_op_stop,
 	.set_retry_limit	= b43_op_set_retry_limit,
 	.set_retry_limit	= b43_op_set_retry_limit,
 	.set_tim		= b43_op_beacon_set_tim,
 	.set_tim		= b43_op_beacon_set_tim,
-	.beacon_update		= b43_op_ibss_beacon_update,
 	.sta_notify		= b43_op_sta_notify,
 	.sta_notify		= b43_op_sta_notify,
 };
 };
 
 

+ 2 - 1
drivers/net/wireless/b43/xmit.c

@@ -317,7 +317,8 @@ int b43_generate_txhdr(struct b43_wldev *dev,
 	/* MAC control */
 	/* MAC control */
 	if (!(info->flags & IEEE80211_TX_CTL_NO_ACK))
 	if (!(info->flags & IEEE80211_TX_CTL_NO_ACK))
 		mac_ctl |= B43_TXH_MAC_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;
 		mac_ctl |= B43_TXH_MAC_HWSEQ;
 	if (info->flags & IEEE80211_TX_CTL_FIRST_FRAGMENT)
 	if (info->flags & IEEE80211_TX_CTL_FIRST_FRAGMENT)
 		mac_ctl |= B43_TXH_MAC_STMSDU;
 		mac_ctl |= B43_TXH_MAC_STMSDU;

+ 17 - 28
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.
 /* Asynchronously update the packet templates in template RAM.
  * Locking: Requires wl->irq_lock to be locked. */
  * 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
 	/* This is the top half of the ansynchronous beacon update. The bottom
 	 * half is the beacon IRQ. Beacon update must be asynchronous to avoid
 	 * half is the beacon IRQ. Beacon update must be asynchronous to avoid
 	 * sending an invalid beacon. This can happen for example, if the
 	 * sending an invalid beacon. This can happen for example, if the
 	 * firmware transmits a beacon while we are updating it. */
 	 * 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)
 	if (wl->current_beacon)
 		dev_kfree_skb_any(wl->current_beacon);
 		dev_kfree_skb_any(wl->current_beacon);
 	wl->current_beacon = 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);
 		memset(wl->bssid, 0, ETH_ALEN);
 	if (b43legacy_status(dev) >= B43legacy_STAT_INITIALIZED) {
 	if (b43legacy_status(dev) >= B43legacy_STAT_INITIALIZED) {
 		if (b43legacy_is_mode(wl, IEEE80211_IF_TYPE_AP)) {
 		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);
 			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);
 		b43legacy_write_mac_bssid_templates(dev);
 	}
 	}
@@ -3394,33 +3405,12 @@ out_unlock:
 
 
 static int b43legacy_op_beacon_set_tim(struct ieee80211_hw *hw,
 static int b43legacy_op_beacon_set_tim(struct ieee80211_hw *hw,
 				       int aid, int set)
 				       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);
 	struct b43legacy_wl *wl = hw_to_b43legacy_wl(hw);
 	unsigned long flags;
 	unsigned long flags;
 
 
 	spin_lock_irqsave(&wl->irq_lock, flags);
 	spin_lock_irqsave(&wl->irq_lock, flags);
-	b43legacy_update_templates(wl, beacon);
+	b43legacy_update_templates(wl);
 	spin_unlock_irqrestore(&wl->irq_lock, flags);
 	spin_unlock_irqrestore(&wl->irq_lock, flags);
 
 
 	return 0;
 	return 0;
@@ -3440,7 +3430,6 @@ static const struct ieee80211_ops b43legacy_hw_ops = {
 	.stop			= b43legacy_op_stop,
 	.stop			= b43legacy_op_stop,
 	.set_retry_limit	= b43legacy_op_set_retry_limit,
 	.set_retry_limit	= b43legacy_op_set_retry_limit,
 	.set_tim		= b43legacy_op_beacon_set_tim,
 	.set_tim		= b43legacy_op_beacon_set_tim,
-	.beacon_update		= b43legacy_op_ibss_beacon_update,
 };
 };
 
 
 /* Hard-reset the chip. Do not call this directly.
 /* Hard-reset the chip. Do not call this directly.

+ 1 - 2
drivers/net/wireless/b43legacy/xmit.c

@@ -295,8 +295,7 @@ static int generate_txhdr_fw3(struct b43legacy_wldev *dev,
 	/* MAC control */
 	/* MAC control */
 	if (!(info->flags & IEEE80211_TX_CTL_NO_ACK))
 	if (!(info->flags & IEEE80211_TX_CTL_NO_ACK))
 		mac_ctl |= B43legacy_TX4_MAC_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;
 		mac_ctl |= B43legacy_TX4_MAC_HWSEQ;
 	if (info->flags & IEEE80211_TX_CTL_FIRST_FRAGMENT)
 	if (info->flags & IEEE80211_TX_CTL_FIRST_FRAGMENT)
 		mac_ctl |= B43legacy_TX4_MAC_STMSDU;
 		mac_ctl |= B43legacy_TX4_MAC_STMSDU;

+ 62 - 84
drivers/net/wireless/iwlwifi/iwl-3945-led.c

@@ -42,14 +42,11 @@
 #include "iwl-3945.h"
 #include "iwl-3945.h"
 #include "iwl-helpers.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 {
 static const struct {
 	u16 brightness;
 	u16 brightness;
 	u8 on_time;
 	u8 on_time;
-	u8 of_time;
+	u8 off_time;
 } blink_tbl[] =
 } blink_tbl[] =
 {
 {
 	{300, 25, 25},
 	{300, 25, 25},
@@ -61,9 +58,16 @@ static const struct {
 	{15, 95, 95 },
 	{15, 95, 95 },
 	{10, 110, 110},
 	{10, 110, 110},
 	{5, 130, 130},
 	{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,
 static int iwl3945_led_cmd_callback(struct iwl3945_priv *priv,
 				    struct iwl3945_cmd *cmd,
 				    struct iwl3945_cmd *cmd,
 				    struct sk_buff *skb)
 				    struct sk_buff *skb)
@@ -71,6 +75,10 @@ static int iwl3945_led_cmd_callback(struct iwl3945_priv *priv,
 	return 1;
 	return 1;
 }
 }
 
 
+static inline int iwl3945_brightness_to_idx(enum led_brightness brightness)
+{
+	return fls(0x000000FF & (u32)brightness);
+}
 
 
 /* Send led command */
 /* Send led command */
 static int iwl_send_led_cmd(struct iwl3945_priv *priv,
 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),
 		.len = sizeof(struct iwl3945_led_cmd),
 		.data = led_cmd,
 		.data = led_cmd,
 		.meta.flags = CMD_ASYNC,
 		.meta.flags = CMD_ASYNC,
-		.meta.u.callback = iwl3945_led_cmd_callback
+		.meta.u.callback = iwl3945_led_cmd_callback,
 	};
 	};
 
 
 	return iwl3945_send_cmd(priv, &cmd);
 	return iwl3945_send_cmd(priv, &cmd);
 }
 }
 
 
 
 
+
 /* Set led on command */
 /* 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 = {
 	struct iwl3945_led_cmd led_cmd = {
 		.id = led_id,
 		.id = led_id,
-		.on = IWL_LED_SOLID,
-		.off = 0,
 		.interval = IWL_DEF_LED_INTRVL
 		.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);
 	return iwl_send_led_cmd(priv, &led_cmd);
 }
 }
 
 
+
+#if 1
 /* Set led on command */
 /* 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 = {
 	struct iwl3945_led_cmd led_cmd = {
 		.id = led_id,
 		.id = led_id,
-		.on = brightness,
-		.off = brightness,
+		.on = IWL_LED_SOLID,
+		.off = 0,
 		.interval = IWL_DEF_LED_INTRVL
 		.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);
 	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 */
 /* Set led off command */
 static int iwl3945_led_off(struct iwl3945_priv *priv, int led_id)
 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);
 	IWL_DEBUG_LED("led off %d\n", led_id);
 	return iwl_send_led_cmd(priv, &led_cmd);
 	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);
 			led->led_off(priv, IWL_LED_LINK);
 		break;
 		break;
 	default:
 	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;
 		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)
 static inline u8 get_blink_rate(struct iwl3945_priv *priv)
 {
 {
 	int index;
 	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)
 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)
 void iwl3945_led_background(struct iwl3945_priv *priv)
 {
 {
-	u8 blink_rate;
+	u8 blink_idx;
 
 
 	if (test_bit(STATUS_EXIT_PENDING, &priv->status)) {
 	if (test_bit(STATUS_EXIT_PENDING, &priv->status)) {
 		priv->last_blink_time = 0;
 		priv->last_blink_time = 0;
@@ -298,9 +280,10 @@ void iwl3945_led_background(struct iwl3945_priv *priv)
 
 
 	if (!priv->allow_blinking) {
 	if (!priv->allow_blinking) {
 		priv->last_blink_time = 0;
 		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;
 		return;
 	}
 	}
@@ -309,21 +292,14 @@ void iwl3945_led_background(struct iwl3945_priv *priv)
 			msecs_to_jiffies(1000)))
 			msecs_to_jiffies(1000)))
 		return;
 		return;
 
 
-	blink_rate = get_blink_rate(priv);
+	blink_idx = get_blink_rate(priv);
 
 
 	/* call only if blink rate change */
 	/* 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;
 	priv->rxtxpackets = 0;
 }
 }
 
 
@@ -337,6 +313,7 @@ int iwl3945_led_register(struct iwl3945_priv *priv)
 
 
 	priv->last_blink_rate = 0;
 	priv->last_blink_rate = 0;
 	priv->rxtxpackets = 0;
 	priv->rxtxpackets = 0;
+	priv->led_tpt = 0;
 	priv->last_blink_time = 0;
 	priv->last_blink_time = 0;
 	priv->allow_blinking = 0;
 	priv->allow_blinking = 0;
 
 
@@ -344,8 +321,8 @@ int iwl3945_led_register(struct iwl3945_priv *priv)
 	snprintf(name, sizeof(name), "iwl-%s:radio",
 	snprintf(name, sizeof(name), "iwl-%s:radio",
 		 wiphy_name(priv->hw->wiphy));
 		 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;
 	priv->led[IWL_LED_TRG_RADIO].led_pattern = NULL;
 
 
 	ret = iwl3945_led_register_led(priv,
 	ret = iwl3945_led_register_led(priv,
@@ -364,8 +341,8 @@ int iwl3945_led_register(struct iwl3945_priv *priv)
 				   IWL_LED_TRG_ASSOC, 0,
 				   IWL_LED_TRG_ASSOC, 0,
 				   name, trigger);
 				   name, trigger);
 	/* for assoc always turn led on */
 	/* 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;
 	priv->led[IWL_LED_TRG_ASSOC].led_pattern = NULL;
 
 
 	if (ret)
 	if (ret)
@@ -391,6 +368,7 @@ int iwl3945_led_register(struct iwl3945_priv *priv)
 	trigger = ieee80211_get_tx_led_name(priv->hw);
 	trigger = ieee80211_get_tx_led_name(priv->hw);
 	snprintf(name, sizeof(name), "iwl-%s:TX",
 	snprintf(name, sizeof(name), "iwl-%s:TX",
 		 wiphy_name(priv->hw->wiphy));
 		 wiphy_name(priv->hw->wiphy));
+
 	ret = iwl3945_led_register_led(priv,
 	ret = iwl3945_led_register_led(priv,
 				   &priv->led[IWL_LED_TRG_TX],
 				   &priv->led[IWL_LED_TRG_TX],
 				   IWL_LED_TRG_TX, 0,
 				   IWL_LED_TRG_TX, 0,

+ 1 - 1
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_on) (struct iwl3945_priv *priv, int led_id);
 	int (*led_off) (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,
 	int (*led_pattern) (struct iwl3945_priv *priv, int led_id,
-			    enum led_brightness brightness);
+			    unsigned int idx);
 
 
 	enum led_type type;
 	enum led_type type;
 	unsigned int registered;
 	unsigned int registered;

+ 25 - 25
drivers/net/wireless/iwlwifi/iwl-3945.c

@@ -514,6 +514,23 @@ static inline void iwl3945_dbg_report_frame(struct iwl3945_priv *priv,
 }
 }
 #endif
 #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,
 static void iwl3945_add_radiotap(struct iwl3945_priv *priv,
 				 struct sk_buff *skb,
 				 struct sk_buff *skb,
@@ -608,12 +625,12 @@ static void iwl3945_add_radiotap(struct iwl3945_priv *priv,
 	stats->flag |= RX_FLAG_RADIOTAP;
 	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 iwl3945_rx_mem_buffer *rxb,
 				   struct ieee80211_rx_status *stats)
 				   struct ieee80211_rx_status *stats)
 {
 {
-	struct ieee80211_hdr *hdr;
 	struct iwl3945_rx_packet *pkt = (struct iwl3945_rx_packet *)rxb->skb->data;
 	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_hdr *rx_hdr = IWL_RX_HDR(pkt);
 	struct iwl3945_rx_frame_end *rx_end = IWL_RX_END(pkt);
 	struct iwl3945_rx_frame_end *rx_end = IWL_RX_END(pkt);
 	short len = le16_to_cpu(rx_hdr->len);
 	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 */
 	/* Set the size of the skb to the size of the frame */
 	skb_put(rxb->skb, le16_to_cpu(rx_hdr->len));
 	skb_put(rxb->skb, le16_to_cpu(rx_hdr->len));
 
 
-	hdr = (void *)rxb->skb->data;
-
 	if (iwl3945_param_hwcrypto)
 	if (iwl3945_param_hwcrypto)
 		iwl3945_set_decrypted_flag(priv, rxb->skb,
 		iwl3945_set_decrypted_flag(priv, rxb->skb,
 				       le32_to_cpu(rx_end->status), stats);
 				       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);
 		iwl3945_add_radiotap(priv, rxb->skb, rx_hdr, stats);
 
 
 #ifdef CONFIG_IWL3945_LEDS
 #ifdef CONFIG_IWL3945_LEDS
-	if (is_data)
+	if (ieee80211_is_data(hdr->frame_control))
 		priv->rxtxpackets += len;
 		priv->rxtxpackets += len;
 #endif
 #endif
 	ieee80211_rx_irqsafe(priv->hw, rxb->skb, stats);
 	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) {
 	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;
 		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;
 		break;
 	}
 	}
-	}
 }
 }
 
 
 int iwl3945_hw_txq_attach_buf_to_tfd(struct iwl3945_priv *priv, void *ptr,
 int iwl3945_hw_txq_attach_buf_to_tfd(struct iwl3945_priv *priv, void *ptr,

+ 1 - 19
drivers/net/wireless/iwlwifi/iwl-3945.h

@@ -510,8 +510,6 @@ struct iwl3945_ucode {
 	u8 data[0];		/* data in same order as "size" elements */
 	u8 data[0];		/* data in same order as "size" elements */
 };
 };
 
 
-#define IWL_IBSS_MAC_HASH_SIZE 32
-
 struct iwl3945_ibss_seq {
 struct iwl3945_ibss_seq {
 	u8 mac[ETH_ALEN];
 	u8 mac[ETH_ALEN];
 	u16 seq_num;
 	u16 seq_num;
@@ -569,17 +567,8 @@ extern int iwl3945_send_add_station(struct iwl3945_priv *priv,
 				struct iwl3945_addsta_cmd *sta, u8 flags);
 				struct iwl3945_addsta_cmd *sta, u8 flags);
 extern u8 iwl3945_add_station(struct iwl3945_priv *priv, const u8 *bssid,
 extern u8 iwl3945_add_station(struct iwl3945_priv *priv, const u8 *bssid,
 			  int is_ap, u8 flags);
 			  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_power_init_handle(struct iwl3945_priv *priv);
 extern int iwl3945_eeprom_init(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 int iwl3945_rx_queue_alloc(struct iwl3945_priv *priv);
 extern void iwl3945_rx_queue_reset(struct iwl3945_priv *priv,
 extern void iwl3945_rx_queue_reset(struct iwl3945_priv *priv,
 			       struct iwl3945_rx_queue *rxq);
 			       struct iwl3945_rx_queue *rxq);
@@ -805,6 +794,7 @@ struct iwl3945_priv {
 	u8 last_blink_rate;
 	u8 last_blink_rate;
 	u8 allow_blinking;
 	u8 allow_blinking;
 	unsigned int rxtxpackets;
 	unsigned int rxtxpackets;
+	u64 led_tpt;
 #endif
 #endif
 
 
 
 
@@ -859,14 +849,6 @@ struct iwl3945_priv {
 	u32 last_beacon_time;
 	u32 last_beacon_time;
 	u64 last_tsf;
 	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 */
 	/* eeprom */
 	struct iwl3945_eeprom eeprom;
 	struct iwl3945_eeprom eeprom;
 
 

+ 1 - 0
drivers/net/wireless/iwlwifi/iwl-4965-hw.h

@@ -819,6 +819,7 @@ enum {
 #define IWL49_NUM_FIFOS 	7
 #define IWL49_NUM_FIFOS 	7
 #define IWL49_CMD_FIFO_NUM	4
 #define IWL49_CMD_FIFO_NUM	4
 #define IWL49_NUM_QUEUES	16
 #define IWL49_NUM_QUEUES	16
+#define IWL49_NUM_AMPDU_QUEUES	8
 
 
 /**
 /**
  * struct iwl_tfd_frame_data
  * struct iwl_tfd_frame_data

+ 0 - 2
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 */
 	/* as default allow aggregation for all tids */
 	lq_sta->tx_agg_tid_en = IWL_AGG_ALL_TID;
 	lq_sta->tx_agg_tid_en = IWL_AGG_ALL_TID;
-#ifdef CONFIG_MAC80211_DEBUGFS
 	lq_sta->drv = priv;
 	lq_sta->drv = priv;
-#endif
 
 
 	rs_initialize_lq(priv, conf, sta);
 	rs_initialize_lq(priv, conf, sta);
 }
 }

+ 36 - 6
drivers/net/wireless/iwlwifi/iwl-4965.c

@@ -49,9 +49,17 @@
 static int iwl4965_send_tx_power(struct iwl_priv *priv);
 static int iwl4965_send_tx_power(struct iwl_priv *priv);
 static int iwl4965_hw_get_temperature(const 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 */
 /* module parameters */
 static struct iwl_mod_params iwl4965_mod_params = {
 static struct iwl_mod_params iwl4965_mod_params = {
 	.num_of_queues = IWL49_NUM_QUEUES,
 	.num_of_queues = IWL49_NUM_QUEUES,
+	.num_of_ampdu_queues = IWL49_NUM_AMPDU_QUEUES,
 	.enable_qos = 1,
 	.enable_qos = 1,
 	.amsdu_size_8K = 1,
 	.amsdu_size_8K = 1,
 	.restart_fw = 1,
 	.restart_fw = 1,
@@ -642,6 +650,18 @@ static void iwl4965_gain_computation(struct iwl_priv *priv,
 	data->beacon_count = 0;
 	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)
 static void iwl4965_bg_txpower_work(struct work_struct *work)
 {
 {
 	struct iwl_priv *priv = container_of(work, struct iwl_priv,
 	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;
 	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;
 		return -EINVAL;
 	}
 	}
 
 
@@ -2000,9 +2022,13 @@ static int iwl4965_txq_agg_enable(struct iwl_priv *priv, int txq_id,
 	int ret;
 	int ret;
 	u16 ra_tid;
 	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);
 	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,
 	.build_addsta_hcmd = iwl4965_build_addsta_hcmd,
 	.chain_noise_reset = iwl4965_chain_noise_reset,
 	.chain_noise_reset = iwl4965_chain_noise_reset,
 	.gain_computation = iwl4965_gain_computation,
 	.gain_computation = iwl4965_gain_computation,
+	.rts_tx_cmd_flag = iwl4965_rts_tx_cmd_flag,
 };
 };
 
 
 static struct iwl_lib_ops iwl4965_lib = {
 static struct iwl_lib_ops iwl4965_lib = {
@@ -2434,6 +2461,9 @@ struct iwl_cfg iwl4965_agn_cfg = {
 	.mod_params = &iwl4965_mod_params,
 	.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_param_named(antenna, iwl4965_mod_params.antenna, int, 0444);
 MODULE_PARM_DESC(antenna, "select antenna (1=Main, 2=Aux, default 0 [both])");
 MODULE_PARM_DESC(antenna, "select antenna (1=Main, 2=Aux, default 0 [both])");
 module_param_named(disable, iwl4965_mod_params.disable, int, 0444);
 module_param_named(disable, iwl4965_mod_params.disable, int, 0444);

+ 1 - 0
drivers/net/wireless/iwlwifi/iwl-5000-hw.h

@@ -81,6 +81,7 @@
 #define IWL50_QUEUE_SIZE                 256
 #define IWL50_QUEUE_SIZE                 256
 #define IWL50_CMD_FIFO_NUM                 7
 #define IWL50_CMD_FIFO_NUM                 7
 #define IWL50_NUM_QUEUES                  20
 #define IWL50_NUM_QUEUES                  20
+#define IWL50_NUM_AMPDU_QUEUES		  10
 #define IWL50_FIRST_AMPDU_QUEUE		  10
 #define IWL50_FIRST_AMPDU_QUEUE		  10
 
 
 #define IWL_sta_id_POS 12
 #define IWL_sta_id_POS 12

+ 42 - 6
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 = {
 static struct iwl_sensitivity_ranges iwl5000_sensitivity = {
 	.min_nrg_cck = 95,
 	.min_nrg_cck = 95,
 	.max_nrg_cck = 0,
 	.max_nrg_cck = 0,
@@ -1006,9 +1016,13 @@ static int iwl5000_txq_agg_enable(struct iwl_priv *priv, int txq_id,
 	int ret;
 	int ret;
 	u16 ra_tid;
 	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);
 	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;
 	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;
 		return -EINVAL;
 	}
 	}
 
 
@@ -1437,6 +1453,7 @@ static struct iwl_hcmd_utils_ops iwl5000_hcmd_utils = {
 	.build_addsta_hcmd = iwl5000_build_addsta_hcmd,
 	.build_addsta_hcmd = iwl5000_build_addsta_hcmd,
 	.gain_computation = iwl5000_gain_computation,
 	.gain_computation = iwl5000_gain_computation,
 	.chain_noise_reset = iwl5000_chain_noise_reset,
 	.chain_noise_reset = iwl5000_chain_noise_reset,
+	.rts_tx_cmd_flag = iwl5000_rts_tx_cmd_flag,
 };
 };
 
 
 static struct iwl_lib_ops iwl5000_lib = {
 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 = {
 static struct iwl_mod_params iwl50_mod_params = {
 	.num_of_queues = IWL50_NUM_QUEUES,
 	.num_of_queues = IWL50_NUM_QUEUES,
+	.num_of_ampdu_queues = IWL50_NUM_AMPDU_QUEUES,
 	.enable_qos = 1,
 	.enable_qos = 1,
 	.amsdu_size_8K = 1,
 	.amsdu_size_8K = 1,
 	.restart_fw = 1,
 	.restart_fw = 1,
@@ -1506,6 +1524,24 @@ struct iwl_cfg iwl5300_agn_cfg = {
 	.mod_params = &iwl50_mod_params,
 	.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 = {
 struct iwl_cfg iwl5100_agn_cfg = {
 	.name = "5100AGN",
 	.name = "5100AGN",
 	.fw_name = "iwlwifi-5000" IWL5000_UCODE_API ".ucode",
 	.fw_name = "iwlwifi-5000" IWL5000_UCODE_API ".ucode",

+ 20 - 10
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_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_PURE_40_MSK	__constant_cpu_to_le32(0x1 << 25)
 #define RXON_FLG_CHANNEL_MODE_MIXED_MSK		__constant_cpu_to_le32(0x2 << 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 */
 /* rx_config filter flags */
 /* accept all data frames */
 /* 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
  * transmission retry.  Device uses cw_max as a bit mask, ANDed with new CW
  * value, to cap the CW value.
  * value, to cap the CW value.
  */
  */
-struct iwl4965_ac_qos {
+struct iwl_ac_qos {
 	__le16 cw_min;
 	__le16 cw_min;
 	__le16 cw_max;
 	__le16 cw_max;
 	u8 aifsn;
 	u8 aifsn;
@@ -745,9 +747,9 @@ struct iwl4965_ac_qos {
  * This command sets up timings for each of the 4 prioritized EDCA Tx FIFOs
  * This command sets up timings for each of the 4 prioritized EDCA Tx FIFOs
  * 0: Background, 1: Best Effort, 2: Video, 3: Voice.
  * 0: Background, 1: Best Effort, 2: Video, 3: Voice.
  */
  */
-struct iwl4965_qosparam_cmd {
+struct iwl_qosparam_cmd {
 	__le32 qos_flags;
 	__le32 qos_flags;
-	struct iwl4965_ac_qos ac[AC_NUM];
+	struct iwl_ac_qos ac[AC_NUM];
 } __attribute__ ((packed));
 } __attribute__ ((packed));
 
 
 /******************************************************************************
 /******************************************************************************
@@ -1139,6 +1141,11 @@ struct iwl4965_rx_mpdu_res_start {
 
 
 /* REPLY_TX Tx flags field */
 /* 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.
 /* 1: Use Request-To-Send protocol before this frame.
  * Mutually exclusive vs. TX_CMD_FLG_CTS_MSK. */
  * Mutually exclusive vs. TX_CMD_FLG_CTS_MSK. */
 #define TX_CMD_FLG_RTS_MSK __constant_cpu_to_le32(1 << 1)
 #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
  * struct iwl_scan_channel - entry in REPLY_SCAN_CMD channel table
  *
  *
@@ -2115,12 +2125,12 @@ struct iwl_scan_channel {
 	/*
 	/*
 	 * type is defined as:
 	 * type is defined as:
 	 * 0:0 1 = active, 0 = passive
 	 * 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.
 	 *     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 tx_gain;		/* gain for analog radio */
 	u8 dsp_atten;		/* gain for DSP */
 	u8 dsp_atten;		/* gain for DSP */
 	__le16 active_dwell;	/* in 1024-uSec TU (time units), typ 5-50 */
 	__le16 active_dwell;	/* in 1024-uSec TU (time units), typ 5-50 */
@@ -2140,9 +2150,9 @@ struct iwl_ssid_ie {
 	u8 ssid[32];
 	u8 ssid[32];
 } __attribute__ ((packed));
 } __attribute__ ((packed));
 
 
-#define PROBE_OPTION_MAX        0x4
+#define PROBE_OPTION_MAX        	0x14
 #define TX_CMD_LIFE_TIME_INFINITE	__constant_cpu_to_le32(0xFFFFFFFF)
 #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
 #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),
  * 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.
  * 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 */
 	__le32 interval;	/* "interval" in uSec */
 	u8 id;			/* 1: Activity, 2: Link, 3: Tech */
 	u8 id;			/* 1: Activity, 2: Link, 3: Tech */
 	u8 off;			/* # intervals off while blinking;
 	u8 off;			/* # intervals off while blinking;

+ 1 - 1
drivers/net/wireless/iwlwifi/iwl-core.c

@@ -825,7 +825,7 @@ int iwl_setup_mac(struct iwl_priv *priv)
 	hw->queues = 4;
 	hw->queues = 4;
 	/* queues to support 11n aggregation */
 	/* queues to support 11n aggregation */
 	if (priv->cfg->sku & IWL_SKU_N)
 	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;
 	hw->conf.beacon_int = 100;
 
 

+ 4 - 1
drivers/net/wireless/iwlwifi/iwl-core.h

@@ -70,7 +70,7 @@ struct iwl_host_cmd;
 struct iwl_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 DRV_COPYRIGHT	"Copyright(c) 2003-2008 Intel Corporation"
 
 
 #define IWL_PCI_DEVICE(dev, subdev, cfg) \
 #define IWL_PCI_DEVICE(dev, subdev, cfg) \
@@ -93,6 +93,8 @@ struct iwl_hcmd_utils_ops {
 			u16 min_average_noise_antennat_i,
 			u16 min_average_noise_antennat_i,
 			u32 min_average_noise);
 			u32 min_average_noise);
 	void (*chain_noise_reset)(struct iwl_priv *priv);
 	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 {
 struct iwl_lib_ops {
@@ -157,6 +159,7 @@ struct iwl_mod_params {
 	int debug;		/* def: 0 = minimal debug log messages */
 	int debug;		/* def: 0 = minimal debug log messages */
 	int disable_hw_scan;	/* def: 0 = use h/w scan */
 	int disable_hw_scan;	/* def: 0 = use h/w scan */
 	int num_of_queues;	/* def: HW dependent */
 	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 enable_qos;		/* def: 1 = use quality of service */
 	int disable_11n;	/* def: 0 = disable 11n capabilities */
 	int disable_11n;	/* def: 0 = disable 11n capabilities */
 	int amsdu_size_8K;	/* def: 1 = enable 8K amsdu size */
 	int amsdu_size_8K;	/* def: 1 = enable 8K amsdu size */

+ 10 - 17
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 iwl5300_agn_cfg;
 extern struct iwl_cfg iwl5100_agn_cfg;
 extern struct iwl_cfg iwl5100_agn_cfg;
 extern struct iwl_cfg iwl5350_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 */
 /* CT-KILL constants */
 #define CT_KILL_THRESHOLD	110 /* in Celsius */
 #define CT_KILL_THRESHOLD	110 /* in Celsius */
@@ -280,7 +276,7 @@ struct iwl_cmd {
 	struct iwl_cmd_header hdr;	/* uCode API */
 	struct iwl_cmd_header hdr;	/* uCode API */
 	union {
 	union {
 		struct iwl_addsta_cmd addsta;
 		struct iwl_addsta_cmd addsta;
-		struct iwl4965_led_cmd led;
+		struct iwl_led_cmd led;
 		u32 flags;
 		u32 flags;
 		u8 val8;
 		u8 val8;
 		u16 val16;
 		u16 val16;
@@ -288,7 +284,7 @@ struct iwl_cmd {
 		struct iwl4965_bt_cmd bt;
 		struct iwl4965_bt_cmd bt;
 		struct iwl4965_rxon_time_cmd rxon_time;
 		struct iwl4965_rxon_time_cmd rxon_time;
 		struct iwl4965_powertable_cmd powertable;
 		struct iwl4965_powertable_cmd powertable;
-		struct iwl4965_qosparam_cmd qosparam;
+		struct iwl_qosparam_cmd qosparam;
 		struct iwl_tx_cmd tx;
 		struct iwl_tx_cmd tx;
 		struct iwl4965_tx_beacon_cmd tx_beacon;
 		struct iwl4965_tx_beacon_cmd tx_beacon;
 		struct iwl4965_rxon_assoc_cmd rxon_assoc;
 		struct iwl4965_rxon_assoc_cmd rxon_assoc;
@@ -433,7 +429,7 @@ struct iwl_ht_info {
 	u8 non_GF_STA_present;
 	u8 non_GF_STA_present;
 };
 };
 
 
-union iwl4965_qos_capabity {
+union iwl_qos_capabity {
 	struct {
 	struct {
 		u8 edca_count:4;	/* bit 0-3 */
 		u8 edca_count:4;	/* bit 0-3 */
 		u8 q_ack:1;		/* bit 4 */
 		u8 q_ack:1;		/* bit 4 */
@@ -454,11 +450,11 @@ union iwl4965_qos_capabity {
 };
 };
 
 
 /* QoS structures */
 /* QoS structures */
-struct iwl4965_qos_info {
+struct iwl_qos_info {
 	int qos_enable;
 	int qos_enable;
 	int qos_active;
 	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
 #define STA_PS_STATUS_WAKE             0
@@ -490,8 +486,6 @@ struct iwl_ucode {
 	u8 data[0];		/* data in same order as "size" elements */
 	u8 data[0];		/* data in same order as "size" elements */
 };
 };
 
 
-#define IWL_IBSS_MAC_HASH_SIZE 32
-
 struct iwl4965_ibss_seq {
 struct iwl4965_ibss_seq {
 	u8 mac[ETH_ALEN];
 	u8 mac[ETH_ALEN];
 	u16 seq_num;
 	u16 seq_num;
@@ -933,7 +927,7 @@ struct iwl_priv {
 #endif
 #endif
 
 
 #ifdef CONFIG_IWLWIFI_LEDS
 #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;
 	unsigned long last_blink_time;
 	u8 last_blink_rate;
 	u8 last_blink_rate;
 	u8 allow_blinking;
 	u8 allow_blinking;
@@ -1042,7 +1036,7 @@ struct iwl_priv {
 	u16 assoc_capability;
 	u16 assoc_capability;
 	u8 ps_mode;
 	u8 ps_mode;
 
 
-	struct iwl4965_qos_info qos_data;
+	struct iwl_qos_info qos_data;
 
 
 	struct workqueue_struct *workqueue;
 	struct workqueue_struct *workqueue;
 
 
@@ -1065,7 +1059,6 @@ struct iwl_priv {
 	struct delayed_work init_alive_start;
 	struct delayed_work init_alive_start;
 	struct delayed_work alive_start;
 	struct delayed_work alive_start;
 	struct delayed_work scan_check;
 	struct delayed_work scan_check;
-	struct delayed_work post_associate;
 	/* TX Power */
 	/* TX Power */
 	s8 tx_power_user_lmt;
 	s8 tx_power_user_lmt;
 	s8 tx_power_channel_lmt;
 	s8 tx_power_channel_lmt;

+ 94 - 113
drivers/net/wireless/iwlwifi/iwl-led.c

@@ -44,14 +44,21 @@
 #include "iwl-io.h"
 #include "iwl-io.h"
 #include "iwl-helpers.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 {
 static const struct {
 	u16 tpt;
 	u16 tpt;
 	u8 on_time;
 	u8 on_time;
-	u8 of_time;
+	u8 off_time;
 } blink_tbl[] =
 } blink_tbl[] =
 {
 {
 	{300, 25, 25},
 	{300, 25, 25},
@@ -63,26 +70,31 @@ static const struct {
 	{15, 95, 95 },
 	{15, 95, 95 },
 	{10, 110, 110},
 	{10, 110, 110},
 	{5, 130, 130},
 	{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 */
 /* 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 = {
 	struct iwl_host_cmd cmd = {
 		.id = REPLY_LEDS_CMD,
 		.id = REPLY_LEDS_CMD,
-		.len = sizeof(struct iwl4965_led_cmd),
+		.len = sizeof(struct iwl_led_cmd),
 		.data = led_cmd,
 		.data = led_cmd,
 		.meta.flags = CMD_ASYNC,
 		.meta.flags = CMD_ASYNC,
-		.meta.u.callback = iwl_led_cmd_callback
+		.meta.u.callback = NULL,
 	};
 	};
 	u32 reg;
 	u32 reg;
 
 
@@ -93,33 +105,20 @@ static int iwl_send_led_cmd(struct iwl_priv *priv,
 	return iwl_send_cmd(priv, &cmd);
 	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,
 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,
 		.id = led_id,
-		.on = brightness,
-		.off = brightness,
 		.interval = IWL_DEF_LED_INTRVL
 		.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);
 	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
 #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 */
 /* Set led off command */
 int iwl4965_led_off(struct iwl_priv *priv, int led_id)
 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,
 		.id = led_id,
 		.on = 0,
 		.on = 0,
 		.off = 0,
 		.off = 0,
@@ -155,25 +166,10 @@ static int iwl4965_led_off_reg(struct iwl_priv *priv, int led_id)
 	return 0;
 	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
  * 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) ||
 	if (test_bit(STATUS_EXIT_PENDING, &priv->status) ||
 	    !test_bit(STATUS_READY, &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
  * 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)
 				       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;
 	struct iwl_priv *priv = led->priv;
 
 
 	if (test_bit(STATUS_EXIT_PENDING, &priv->status))
 	if (test_bit(STATUS_EXIT_PENDING, &priv->status))
 		return;
 		return;
 
 
+
+	IWL_DEBUG_LED("Led type = %s brightness = %d\n",
+			led_type_str[led->type], brightness);
 	switch (brightness) {
 	switch (brightness) {
 	case LED_FULL:
 	case LED_FULL:
 		if (led->type == IWL_LED_TRG_ASSOC)
 		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);
 			led->led_off(priv, IWL_LED_LINK);
 		break;
 		break;
 	default:
 	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;
 		break;
 	}
 	}
 }
 }
@@ -226,8 +226,7 @@ static void iwl4965_led_brightness_set(struct led_classdev *led_cdev,
 /*
 /*
  * Register led class with the system
  * 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,
 				   enum led_type type, u8 set_led,
 				   const char *name, char *trigger)
 				   const char *name, char *trigger)
 {
 {
@@ -235,7 +234,7 @@ static int iwl_leds_register_led(struct iwl_priv *priv,
 	int ret;
 	int ret;
 
 
 	led->led_dev.name = name;
 	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->led_dev.default_trigger = trigger;
 
 
 	led->priv = priv;
 	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
  * 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;
 	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;
 	s64 tpt = current_tpt - priv->led_tpt;
 
 
 	if (tpt < 0) /* wrapparound */
 	if (tpt < 0) /* wrapparound */
 		tpt = -tpt;
 		tpt = -tpt;
 
 
+	IWL_DEBUG_LED("tpt %lld current_tpt %lld\n", tpt, current_tpt);
 	priv->led_tpt = current_tpt;
 	priv->led_tpt = current_tpt;
 
 
-	if (tpt < IWL_LED_THRESHOLD) {
+	if (!priv->allow_blinking)
 		i = IWL_MAX_BLINK_TBL;
 		i = IWL_MAX_BLINK_TBL;
-	} else {
+	else
 		for (i = 0; i < IWL_MAX_BLINK_TBL; i++)
 		for (i = 0; i < IWL_MAX_BLINK_TBL; i++)
 			if (tpt  > (blink_tbl[i].tpt * IWL_1MB_RATE))
 			if (tpt  > (blink_tbl[i].tpt * IWL_1MB_RATE))
 				break;
 				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)
 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)
 void iwl_leds_background(struct iwl_priv *priv)
 {
 {
-	u8 blink_rate;
+	u8 blink_idx;
 
 
 	if (test_bit(STATUS_EXIT_PENDING, &priv->status)) {
 	if (test_bit(STATUS_EXIT_PENDING, &priv->status)) {
 		priv->last_blink_time = 0;
 		priv->last_blink_time = 0;
@@ -313,9 +308,10 @@ void iwl_leds_background(struct iwl_priv *priv)
 
 
 	if (!priv->allow_blinking) {
 	if (!priv->allow_blinking) {
 		priv->last_blink_time = 0;
 		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;
 		return;
 	}
 	}
@@ -324,21 +320,14 @@ void iwl_leds_background(struct iwl_priv *priv)
 			msecs_to_jiffies(1000)))
 			msecs_to_jiffies(1000)))
 		return;
 		return;
 
 
-	blink_rate = get_blink_rate(priv);
+	blink_idx = iwl_get_blink_rate(priv);
 
 
 	/* call only if blink rate change */
 	/* 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);
 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_off = iwl4965_led_off_reg;
 	priv->led[IWL_LED_TRG_RADIO].led_pattern = NULL;
 	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)
 	if (ret)
 		goto exit_fail;
 		goto exit_fail;
 
 
@@ -373,10 +360,9 @@ int iwl_leds_register(struct iwl_priv *priv)
 	snprintf(name, sizeof(name), "iwl-%s:assoc",
 	snprintf(name, sizeof(name), "iwl-%s:assoc",
 		 wiphy_name(priv->hw->wiphy));
 		 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 */
 	/* 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_on = iwl4965_led_on_reg;
 	priv->led[IWL_LED_TRG_ASSOC].led_off = 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;
 		goto exit_fail;
 
 
 	trigger = ieee80211_get_rx_led_name(priv->hw);
 	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;
 	priv->led[IWL_LED_TRG_RX].led_pattern = iwl4965_led_pattern;
 
 
 	if (ret)
 	if (ret)
 		goto exit_fail;
 		goto exit_fail;
 
 
 	trigger = ieee80211_get_tx_led_name(priv->hw);
 	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;
 	priv->led[IWL_LED_TRG_TX].led_pattern = iwl4965_led_pattern;
 
 
 	if (ret)
 	if (ret)
@@ -425,7 +406,7 @@ exit_fail:
 EXPORT_SYMBOL(iwl_leds_register);
 EXPORT_SYMBOL(iwl_leds_register);
 
 
 /* unregister led class */
 /* 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)
 	if (!led->registered)
 		return;
 		return;

+ 2 - 3
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 iwl_priv *priv;
 	struct led_classdev led_dev;
 	struct led_classdev led_dev;
 
 
 	int (*led_on) (struct iwl_priv *priv, int led_id);
 	int (*led_on) (struct iwl_priv *priv, int led_id);
 	int (*led_off) (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;
 	enum led_type type;
 	unsigned int registered;
 	unsigned int registered;

+ 17 - 20
drivers/net/wireless/iwlwifi/iwl-rx.c

@@ -29,6 +29,7 @@
 
 
 #include <linux/etherdevice.h>
 #include <linux/etherdevice.h>
 #include <net/mac80211.h>
 #include <net/mac80211.h>
+#include <asm/unaligned.h>
 #include "iwl-eeprom.h"
 #include "iwl-eeprom.h"
 #include "iwl-dev.h"
 #include "iwl-dev.h"
 #include "iwl-core.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;
 	iwl4965_rt->rt_hdr.it_pad = 0;
 
 
 	/* total header + data */
 	/* 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 */
 	/* 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 */
 	/* Zero the flags, we'll add to them as we go */
 	iwl4965_rt->rt_flags = 0;
 	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_dbmsignal = signal;
 	iwl4965_rt->rt_dbmnoise = noise;
 	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 */
 	/* Convert the channel frequency and set the flags */
 	put_unaligned(cpu_to_le16(stats->freq), &iwl4965_rt->rt_channelMHz);
 	put_unaligned(cpu_to_le16(stats->freq), &iwl4965_rt->rt_channelMHz);
 	if (!(phy_flags_hw & RX_RES_PHY_FLAGS_BAND_24_MSK))
 	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)
 	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 */
 	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)
 	if (rate == -1)
 		iwl4965_rt->rt_rate = 0;
 		iwl4965_rt->rt_rate = 0;

+ 55 - 48
drivers/net/wireless/iwlwifi/iwl-scan.c

@@ -38,8 +38,11 @@
 /* For active scan, listen ACTIVE_DWELL_TIME (msec) on each channel after
 /* 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
  * sending probe req.  This should be set long enough to hear probe responses
  * from more than one AP.  */
  * 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
 /* For faster active scanning, scan will move to the next channel if fewer than
  * PLCP_QUIET_THRESH packets are heard on this channel within
  * PLCP_QUIET_THRESH packets are heard on this channel within
@@ -48,7 +51,7 @@
  * no other traffic).
  * no other traffic).
  * Disable "quiet" feature by setting PLCP_QUIET_THRESH to 0. */
  * Disable "quiet" feature by setting PLCP_QUIET_THRESH to 0. */
 #define IWL_PLCP_QUIET_THRESH       __constant_cpu_to_le16(1)  /* packets */
 #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.
 /* For passive scan, listen PASSIVE_DWELL_TIME (msec) on each channel.
  * Must be set longer than active dwell time.
  * Must be set longer than active dwell time.
@@ -58,10 +61,15 @@
 #define IWL_PASSIVE_DWELL_BASE      (100)
 #define IWL_PASSIVE_DWELL_BASE      (100)
 #define IWL_CHANNEL_TUNE_TIME       5
 #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] = {
 static int scan_tx_ant[3] = {
 	RATE_MCS_ANT_A_MSK, RATE_MCS_ANT_B_MSK, RATE_MCS_ANT_C_MSK
 	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)
 static int iwl_is_empty_essid(const char *essid, int essid_len)
 {
 {
 	/* Single white space is for Linksys APs */
 	/* 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",
 		       "(TSF: 0x%08X:%08X) - %d (beacon timer %u)\n",
 		       notif->channel,
 		       notif->channel,
 		       notif->band ? "bg" : "a",
 		       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) */
 /* 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);
 EXPORT_SYMBOL(iwl_setup_rx_scan_handlers);
 
 
 static inline u16 iwl_get_active_dwell_time(struct iwl_priv *priv,
 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)
 	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
 	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,
 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_24 :
 	    IWL_PASSIVE_DWELL_BASE + IWL_PASSIVE_DWELL_TIME_52;
 	    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;
 		passive = (passive * 98) / 100 - IWL_CHANNEL_TUNE_TIME * 2;
 	}
 	}
 
 
-	if (passive <= active)
-		passive = active + 1;
-
 	return passive;
 	return passive;
 }
 }
 
 
 static int iwl_get_channels_for_scan(struct iwl_priv *priv,
 static int iwl_get_channels_for_scan(struct iwl_priv *priv,
 				     enum ieee80211_band band,
 				     enum ieee80211_band band,
-				     u8 is_active, u8 direct_mask,
+				     u8 is_active, u8 n_probes,
 				     struct iwl_scan_channel *scan_ch)
 				     struct iwl_scan_channel *scan_ch)
 {
 {
 	const struct ieee80211_channel *channels = NULL;
 	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 passive_dwell = 0;
 	u16 active_dwell = 0;
 	u16 active_dwell = 0;
 	int added, i;
 	int added, i;
+	u16 channel;
 
 
 	sband = iwl_get_hw_mode(priv, band);
 	sband = iwl_get_hw_mode(priv, band);
 	if (!sband)
 	if (!sband)
@@ -382,31 +391,35 @@ static int iwl_get_channels_for_scan(struct iwl_priv *priv,
 
 
 	channels = sband->channels;
 	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);
 	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++) {
 	for (i = 0, added = 0; i < sband->n_channels; i++) {
 		if (channels[i].flags & IEEE80211_CHAN_DISABLED)
 		if (channels[i].flags & IEEE80211_CHAN_DISABLED)
 			continue;
 			continue;
 
 
-		scan_ch->channel =
+		channel =
 			ieee80211_frequency_to_channel(channels[i].center_freq);
 			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)) {
 		if (!is_channel_valid(ch_info)) {
 			IWL_DEBUG_SCAN("Channel %d is INVALID for this band.\n",
 			IWL_DEBUG_SCAN("Channel %d is INVALID for this band.\n",
-				       scan_ch->channel);
+					channel);
 			continue;
 			continue;
 		}
 		}
 
 
 		if (!is_active || is_channel_passive(ch_info) ||
 		if (!is_active || is_channel_passive(ch_info) ||
 		    (channels[i].flags & IEEE80211_CHAN_PASSIVE_SCAN))
 		    (channels[i].flags & IEEE80211_CHAN_PASSIVE_SCAN))
-			scan_ch->type = 0;
+			scan_ch->type = SCAN_CHANNEL_TYPE_PASSIVE;
 		else
 		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->active_dwell = cpu_to_le16(active_dwell);
 		scan_ch->passive_dwell = cpu_to_le16(passive_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 */
 		/* Set txpower levels to defaults */
 		scan_ch->dsp_atten = 110;
 		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)
 		if (band == IEEE80211_BAND_5GHZ)
 			scan_ch->tx_gain = ((1 << 5) | (3 << 3)) | 3;
 			scan_ch->tx_gain = ((1 << 5) | (3 << 3)) | 3;
-		else {
+		else
 			scan_ch->tx_gain = ((1 << 5) | (5 << 3));
 			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);
 			       active_dwell : passive_dwell);
 
 
 		scan_ch++;
 		scan_ch++;
@@ -673,7 +686,7 @@ static u32 iwl_scan_tx_ant(struct iwl_priv *priv, enum ieee80211_band band)
 			break;
 			break;
 		}
 		}
 	}
 	}
-
+	IWL_DEBUG_SCAN("select TX ANT = %c\n", 'A' + ind);
 	return scan_tx_ant[ind];
 	return scan_tx_ant[ind];
 }
 }
 
 
@@ -693,7 +706,7 @@ static void iwl_bg_request_scan(struct work_struct *data)
 	u32 tx_ant;
 	u32 tx_ant;
 	u16 cmd_len;
 	u16 cmd_len;
 	enum ieee80211_band band;
 	enum ieee80211_band band;
-	u8 direct_mask;
+	u8 n_probes = 2;
 	u8 rx_chain = 0x7; /* bitmap: ABC chains */
 	u8 rx_chain = 0x7; /* bitmap: ABC chains */
 
 
 	conf = ieee80211_get_hw_conf(priv->hw);
 	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;
 		scan->direct_scan[0].len = priv->direct_ssid_len;
 		memcpy(scan->direct_scan[0].ssid,
 		memcpy(scan->direct_scan[0].ssid,
 		       priv->direct_ssid, priv->direct_ssid_len);
 		       priv->direct_ssid, priv->direct_ssid_len);
-		direct_mask = 1;
+		n_probes++;
 	} else if (!iwl_is_associated(priv) && priv->essid_len) {
 	} else if (!iwl_is_associated(priv) && priv->essid_len) {
 		IWL_DEBUG_SCAN("Start direct scan for '%s' (not associated)\n",
 		IWL_DEBUG_SCAN("Start direct scan for '%s' (not associated)\n",
 				iwl_escape_essid(priv->essid, priv->essid_len));
 				iwl_escape_essid(priv->essid, priv->essid_len));
 		scan->direct_scan[0].id = WLAN_EID_SSID;
 		scan->direct_scan[0].id = WLAN_EID_SSID;
 		scan->direct_scan[0].len = priv->essid_len;
 		scan->direct_scan[0].len = priv->essid_len;
 		memcpy(scan->direct_scan[0].ssid, priv->essid, priv->essid_len);
 		memcpy(scan->direct_scan[0].ssid, priv->essid, priv->essid_len);
-		direct_mask = 1;
+		n_probes++;
 	} else {
 	} else {
 		IWL_DEBUG_SCAN("Start indirect scan.\n");
 		IWL_DEBUG_SCAN("Start indirect scan.\n");
-		direct_mask = 0;
 	}
 	}
 
 
 	scan->tx_cmd.tx_flags = TX_CMD_FLG_SEQ_CTL_MSK;
 	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 |
 	scan->filter_flags |= (RXON_FILTER_ACCEPT_GRP_MSK |
 			       RXON_FILTER_BCON_AWARE_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) {
 	if (scan->channel_count == 0) {
 		IWL_DEBUG_SCAN("channel count %d\n", scan->channel_count);
 		IWL_DEBUG_SCAN("channel count %d\n", scan->channel_count);
 		goto done;
 		goto done;

+ 1 - 7
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;
 		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))
 	if ((tx_flags & TX_CMD_FLG_RTS_MSK) || (tx_flags & TX_CMD_FLG_CTS_MSK))
 		tx_flags |= TX_CMD_FLG_FULL_TXOP_PROT_MSK;
 		tx_flags |= TX_CMD_FLG_FULL_TXOP_PROT_MSK;

+ 16 - 129
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;
 	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
  * 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;
 	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 MAX_UCODE_BEACON_INTERVAL	1024
 #define INTEL_CONN_LISTEN_INTERVAL	__constant_cpu_to_le16(0xA)
 #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
 #ifdef CONFIG_IWL3945_SPECTRUM_MEASUREMENT
 
 
 #include "iwl-spectrum.h"
 #include "iwl-spectrum.h"
@@ -6531,8 +6421,6 @@ static void iwl3945_bg_post_associate(struct work_struct *data)
 		break;
 		break;
 	}
 	}
 
 
-	iwl3945_sequence_reset(priv);
-
 	iwl3945_activate_qos(priv, 0);
 	iwl3945_activate_qos(priv, 0);
 
 
 	/* we have just associated, don't start scan too early */
 	/* 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... */
 	 * 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,
 static int iwl3945_mac_config_interface(struct ieee80211_hw *hw,
 					struct ieee80211_vif *vif,
 					struct ieee80211_vif *vif,
 				    struct ieee80211_if_conf *conf)
 				    struct ieee80211_if_conf *conf)
@@ -6924,10 +6815,21 @@ static int iwl3945_mac_config_interface(struct ieee80211_hw *hw,
 		return 0;
 		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 */
 	/* XXX: this MUST use conf->mac_addr */
 
 
 	if ((priv->iw_mode == IEEE80211_IF_TYPE_AP) &&
 	if ((priv->iw_mode == IEEE80211_IF_TYPE_AP) &&
-	    (!conf->beacon || !conf->ssid_len)) {
+	    (!conf->ssid_len)) {
 		IWL_DEBUG_MAC80211
 		IWL_DEBUG_MAC80211
 		    ("Leaving in AP mode because HostAPD is not ready.\n");
 		    ("Leaving in AP mode because HostAPD is not ready.\n");
 		return 0;
 		return 0;
@@ -6959,7 +6861,7 @@ static int iwl3945_mac_config_interface(struct ieee80211_hw *hw,
 		if (priv->ibss_beacon)
 		if (priv->ibss_beacon)
 			dev_kfree_skb(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))
 	if (iwl3945_is_rfkill(priv))
@@ -7940,7 +7842,6 @@ static struct ieee80211_ops iwl3945_hw_ops = {
 	.conf_tx = iwl3945_mac_conf_tx,
 	.conf_tx = iwl3945_mac_conf_tx,
 	.get_tsf = iwl3945_mac_get_tsf,
 	.get_tsf = iwl3945_mac_get_tsf,
 	.reset_tsf = iwl3945_mac_reset_tsf,
 	.reset_tsf = iwl3945_mac_reset_tsf,
-	.beacon_update = iwl3945_mac_beacon_update,
 	.hw_scan = iwl3945_mac_hw_scan
 	.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 iwl3945_priv *priv;
 	struct ieee80211_hw *hw;
 	struct ieee80211_hw *hw;
 	struct iwl_3945_cfg *cfg = (struct iwl_3945_cfg *)(ent->driver_data);
 	struct iwl_3945_cfg *cfg = (struct iwl_3945_cfg *)(ent->driver_data);
-	int i;
 	unsigned long flags;
 	unsigned long flags;
 	DECLARE_MAC_BUF(mac);
 	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->sta_lock);
 	spin_lock_init(&priv->hcmd_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);
 	INIT_LIST_HEAD(&priv->free_frames);
 
 
 	mutex_init(&priv->mutex);
 	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)
 static void __devexit iwl3945_pci_remove(struct pci_dev *pdev)
 {
 {
 	struct iwl3945_priv *priv = pci_get_drvdata(pdev);
 	struct iwl3945_priv *priv = pci_get_drvdata(pdev);
-	struct list_head *p, *q;
-	int i;
 	unsigned long flags;
 	unsigned long flags;
 
 
 	if (!priv)
 	if (!priv)
@@ -8208,14 +8103,6 @@ static void __devexit iwl3945_pci_remove(struct pci_dev *pdev)
 
 
 	iwl_synchronize_irq(priv);
 	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);
 	sysfs_remove_group(&pdev->dev.kobj, &iwl3945_attribute_group);
 
 
 	iwl3945_rfkill_unregister(priv);
 	iwl3945_rfkill_unregister(priv);

+ 52 - 56
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 */
 	/* always get timestamp with Rx frame */
 	priv->staging_rxon.flags |= RXON_FLG_TSF2HOST_MSK;
 	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);
 	ret = iwl4965_check_rxon_cmd(&priv->staging_rxon);
 	if (ret) {
 	if (ret) {
@@ -325,16 +328,6 @@ static int iwl4965_commit_rxon(struct iwl_priv *priv)
 	if (!priv->error_recovering)
 	if (!priv->error_recovering)
 		priv->start_calib = 0;
 		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 */
 	/* Add the broadcast address so we can send broadcast frames */
 	if (iwl_rxon_add_station(priv, iwl_bcast_addr, 0) ==
 	if (iwl_rxon_add_station(priv, iwl_bcast_addr, 0) ==
 						IWL_INVALID_STATION) {
 						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));
 		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;
 	return 0;
 }
 }
 
 
@@ -572,25 +575,14 @@ static void iwl4965_ht_conf(struct iwl_priv *priv,
 /*
 /*
  * QoS  support
  * 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))
 	if (test_bit(STATUS_EXIT_PENDING, &priv->status))
 		return;
 		return;
 
 
 	if (!priv->qos_data.qos_enable)
 	if (!priv->qos_data.qos_enable)
 		return;
 		return;
 
 
-	spin_lock_irqsave(&priv->lock, flags);
 	priv->qos_data.def_qos_parm.qos_flags = 0;
 	priv->qos_data.def_qos_parm.qos_flags = 0;
 
 
 	if (priv->qos_data.qos_cap.q_AP.queue_request &&
 	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)
 	if (priv->current_ht_config.is_ht)
 		priv->qos_data.def_qos_parm.qos_flags |= QOS_PARAM_FLG_TGN_MSK;
 		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)) {
 	if (force || iwl_is_associated(priv)) {
 		IWL_DEBUG_QOS("send QoS cmd with Qos active=%d FLAGS=0x%X\n",
 		IWL_DEBUG_QOS("send QoS cmd with Qos active=%d FLAGS=0x%X\n",
 				priv->qos_data.qos_active,
 				priv->qos_data.qos_active,
 				priv->qos_data.def_qos_parm.qos_flags);
 				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;
 	struct ieee80211_conf *conf = NULL;
 	int ret = 0;
 	int ret = 0;
 	DECLARE_MAC_BUF(mac);
 	DECLARE_MAC_BUF(mac);
+	unsigned long flags;
 
 
 	if (priv->iw_mode == IEEE80211_IF_TYPE_AP) {
 	if (priv->iw_mode == IEEE80211_IF_TYPE_AP) {
 		IWL_ERROR("%s Should not be called in AP mode\n", __FUNCTION__);
 		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)
 	if (priv->iw_mode == IEEE80211_IF_TYPE_IBSS)
 		priv->assoc_station_added = 1;
 		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);
 	iwl_power_update_mode(priv, 0);
 	/* we have just associated, don't start scan too early */
 	/* we have just associated, don't start scan too early */
 	priv->next_scan_jiffies = jiffies + IWL_DELAY_NEXT_SCAN;
 	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 int iwl4965_mac_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf);
 
 
 static void iwl_bg_scan_completed(struct work_struct *work)
 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);
 		mutex_lock(&priv->mutex);
 		iwl_scan_cancel_timeout(priv, 100);
 		iwl_scan_cancel_timeout(priv, 100);
-		cancel_delayed_work(&priv->post_associate);
 		mutex_unlock(&priv->mutex);
 		mutex_unlock(&priv->mutex);
 	}
 	}
 
 
@@ -2855,6 +2836,7 @@ out:
 static void iwl4965_config_ap(struct iwl_priv *priv)
 static void iwl4965_config_ap(struct iwl_priv *priv)
 {
 {
 	int ret = 0;
 	int ret = 0;
+	unsigned long flags;
 
 
 	if (test_bit(STATUS_EXIT_PENDING, &priv->status))
 	if (test_bit(STATUS_EXIT_PENDING, &priv->status))
 		return;
 		return;
@@ -2902,7 +2884,9 @@ static void iwl4965_config_ap(struct iwl_priv *priv)
 		/* restore RXON assoc */
 		/* restore RXON assoc */
 		priv->staging_rxon.filter_flags |= RXON_FILTER_ASSOC_MSK;
 		priv->staging_rxon.filter_flags |= RXON_FILTER_ASSOC_MSK;
 		iwl4965_commit_rxon(priv);
 		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);
 		iwl_rxon_add_station(priv, iwl_bcast_addr, 0);
 	}
 	}
 	iwl4965_send_beacon_cmd(priv);
 	iwl4965_send_beacon_cmd(priv);
@@ -2912,6 +2896,9 @@ static void iwl4965_config_ap(struct iwl_priv *priv)
 	 * clear sta table, add BCAST sta... */
 	 * 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,
 static int iwl4965_mac_config_interface(struct ieee80211_hw *hw,
 					struct ieee80211_vif *vif,
 					struct ieee80211_vif *vif,
 				    struct ieee80211_if_conf *conf)
 				    struct ieee80211_if_conf *conf)
@@ -2929,8 +2916,18 @@ static int iwl4965_mac_config_interface(struct ieee80211_hw *hw,
 		return 0;
 		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) &&
 	if ((priv->iw_mode == IEEE80211_IF_TYPE_AP) &&
-	    (!conf->beacon || !conf->ssid_len)) {
+	    (!conf->ssid_len)) {
 		IWL_DEBUG_MAC80211
 		IWL_DEBUG_MAC80211
 		    ("Leaving in AP mode because HostAPD is not ready.\n");
 		    ("Leaving in AP mode because HostAPD is not ready.\n");
 		return 0;
 		return 0;
@@ -2962,7 +2959,7 @@ static int iwl4965_mac_config_interface(struct ieee80211_hw *hw,
 		if (priv->ibss_beacon)
 		if (priv->ibss_beacon)
 			dev_kfree_skb(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))
 	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)) {
 	if (iwl_is_ready_rf(priv)) {
 		iwl_scan_cancel_timeout(priv, 100);
 		iwl_scan_cancel_timeout(priv, 100);
-		cancel_delayed_work(&priv->post_associate);
 		priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
 		priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
 		iwl4965_commit_rxon(priv);
 		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.def_qos_parm.ac[q].reserved1 = 0;
 	priv->qos_data.qos_active = 1;
 	priv->qos_data.qos_active = 1;
 
 
-	spin_unlock_irqrestore(&priv->lock, flags);
-
-	mutex_lock(&priv->mutex);
 	if (priv->iw_mode == IEEE80211_IF_TYPE_AP)
 	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))
 	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");
 	IWL_DEBUG_MAC80211("leave\n");
 	return 0;
 	return 0;
@@ -3413,8 +3406,6 @@ static void iwl4965_mac_reset_tsf(struct ieee80211_hw *hw)
 
 
 	iwl_reset_qos(priv);
 	iwl_reset_qos(priv);
 
 
-	cancel_delayed_work(&priv->post_associate);
-
 	spin_lock_irqsave(&priv->lock, flags);
 	spin_lock_irqsave(&priv->lock, flags);
 	priv->assoc_id = 0;
 	priv->assoc_id = 0;
 	priv->assoc_capability = 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->beacon_update, iwl4965_bg_beacon_update);
 	INIT_WORK(&priv->set_monitor, iwl4965_bg_set_monitor);
 	INIT_WORK(&priv->set_monitor, iwl4965_bg_set_monitor);
 	INIT_WORK(&priv->run_time_calib_work, iwl_bg_run_time_calib_work);
 	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->init_alive_start, iwl_bg_init_alive_start);
 	INIT_DELAYED_WORK(&priv->alive_start, iwl_bg_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_sync(&priv->init_alive_start);
 	cancel_delayed_work(&priv->scan_check);
 	cancel_delayed_work(&priv->scan_check);
 	cancel_delayed_work(&priv->alive_start);
 	cancel_delayed_work(&priv->alive_start);
-	cancel_delayed_work(&priv->post_associate);
 	cancel_work_sync(&priv->beacon_update);
 	cancel_work_sync(&priv->beacon_update);
 	del_timer_sync(&priv->statistics_periodic);
 	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,
 	.get_tx_stats = iwl4965_mac_get_tx_stats,
 	.conf_tx = iwl4965_mac_conf_tx,
 	.conf_tx = iwl4965_mac_conf_tx,
 	.reset_tsf = iwl4965_mac_reset_tsf,
 	.reset_tsf = iwl4965_mac_reset_tsf,
-	.beacon_update = iwl4965_mac_beacon_update,
 	.bss_info_changed = iwl4965_bss_info_changed,
 	.bss_info_changed = iwl4965_bss_info_changed,
 	.ampdu_action = iwl4965_mac_ampdu_action,
 	.ampdu_action = iwl4965_mac_ampdu_action,
 	.hw_scan = iwl4965_mac_hw_scan
 	.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(0x4229, PCI_ANY_ID, iwl4965_agn_cfg)},
 	{IWL_PCI_DEVICE(0x4230, PCI_ANY_ID, iwl4965_agn_cfg)},
 	{IWL_PCI_DEVICE(0x4230, PCI_ANY_ID, iwl4965_agn_cfg)},
 #ifdef CONFIG_IWL5000
 #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(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)},
 	{IWL_PCI_DEVICE(0x423A, PCI_ANY_ID, iwl5350_agn_cfg)},
 #endif /* CONFIG_IWL5000 */
 #endif /* CONFIG_IWL5000 */
 	{0}
 	{0}

+ 1 - 1
drivers/net/wireless/mac80211_hwsim.c

@@ -126,7 +126,7 @@ static void mac80211_hwsim_monitor_rx(struct ieee80211_hw *hw,
 					  (1 << IEEE80211_RADIOTAP_CHANNEL));
 					  (1 << IEEE80211_RADIOTAP_CHANNEL));
 	hdr->rt_flags = 0;
 	hdr->rt_flags = 0;
 	hdr->rt_rate = txrate->bitrate / 5;
 	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;
 	flags = IEEE80211_CHAN_2GHZ;
 	if (txrate->flags & IEEE80211_RATE_ERP_G)
 	if (txrate->flags & IEEE80211_RATE_ERP_G)
 		flags |= IEEE80211_CHAN_OFDM;
 		flags |= IEEE80211_CHAN_OFDM;

+ 35 - 54
drivers/net/wireless/rt2x00/rt2400pci.c

@@ -1069,6 +1069,40 @@ static void rt2400pci_write_tx_desc(struct rt2x00_dev *rt2x00dev,
 /*
 /*
  * TX data initialization
  * 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,
 static void rt2400pci_kick_tx_queue(struct rt2x00_dev *rt2x00dev,
 				    const enum data_queue_qid queue)
 				    const enum data_queue_qid queue)
 {
 {
@@ -1515,59 +1549,6 @@ static u64 rt2400pci_get_tsf(struct ieee80211_hw *hw)
 	return tsf;
 	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)
 static int rt2400pci_tx_last_beacon(struct ieee80211_hw *hw)
 {
 {
 	struct rt2x00_dev *rt2x00dev = hw->priv;
 	struct rt2x00_dev *rt2x00dev = hw->priv;
@@ -1592,7 +1573,6 @@ static const struct ieee80211_ops rt2400pci_mac80211_ops = {
 	.conf_tx		= rt2400pci_conf_tx,
 	.conf_tx		= rt2400pci_conf_tx,
 	.get_tx_stats		= rt2x00mac_get_tx_stats,
 	.get_tx_stats		= rt2x00mac_get_tx_stats,
 	.get_tsf		= rt2400pci_get_tsf,
 	.get_tsf		= rt2400pci_get_tsf,
-	.beacon_update		= rt2400pci_beacon_update,
 	.tx_last_beacon		= rt2400pci_tx_last_beacon,
 	.tx_last_beacon		= rt2400pci_tx_last_beacon,
 };
 };
 
 
@@ -1610,6 +1590,7 @@ static const struct rt2x00lib_ops rt2400pci_rt2x00_ops = {
 	.link_tuner		= rt2400pci_link_tuner,
 	.link_tuner		= rt2400pci_link_tuner,
 	.write_tx_desc		= rt2400pci_write_tx_desc,
 	.write_tx_desc		= rt2400pci_write_tx_desc,
 	.write_tx_data		= rt2x00pci_write_tx_data,
 	.write_tx_data		= rt2x00pci_write_tx_data,
+	.write_beacon		= rt2400pci_write_beacon,
 	.kick_tx_queue		= rt2400pci_kick_tx_queue,
 	.kick_tx_queue		= rt2400pci_kick_tx_queue,
 	.fill_rxdone		= rt2400pci_fill_rxdone,
 	.fill_rxdone		= rt2400pci_fill_rxdone,
 	.config_filter		= rt2400pci_config_filter,
 	.config_filter		= rt2400pci_config_filter,

+ 35 - 55
drivers/net/wireless/rt2x00/rt2500pci.c

@@ -1227,6 +1227,40 @@ static void rt2500pci_write_tx_desc(struct rt2x00_dev *rt2x00dev,
 /*
 /*
  * TX data initialization
  * 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,
 static void rt2500pci_kick_tx_queue(struct rt2x00_dev *rt2x00dev,
 				    const enum data_queue_qid queue)
 				    const enum data_queue_qid queue)
 {
 {
@@ -1808,60 +1842,6 @@ static u64 rt2500pci_get_tsf(struct ieee80211_hw *hw)
 	return tsf;
 	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)
 static int rt2500pci_tx_last_beacon(struct ieee80211_hw *hw)
 {
 {
 	struct rt2x00_dev *rt2x00dev = hw->priv;
 	struct rt2x00_dev *rt2x00dev = hw->priv;
@@ -1886,7 +1866,6 @@ static const struct ieee80211_ops rt2500pci_mac80211_ops = {
 	.conf_tx		= rt2x00mac_conf_tx,
 	.conf_tx		= rt2x00mac_conf_tx,
 	.get_tx_stats		= rt2x00mac_get_tx_stats,
 	.get_tx_stats		= rt2x00mac_get_tx_stats,
 	.get_tsf		= rt2500pci_get_tsf,
 	.get_tsf		= rt2500pci_get_tsf,
-	.beacon_update		= rt2500pci_beacon_update,
 	.tx_last_beacon		= rt2500pci_tx_last_beacon,
 	.tx_last_beacon		= rt2500pci_tx_last_beacon,
 };
 };
 
 
@@ -1904,6 +1883,7 @@ static const struct rt2x00lib_ops rt2500pci_rt2x00_ops = {
 	.link_tuner		= rt2500pci_link_tuner,
 	.link_tuner		= rt2500pci_link_tuner,
 	.write_tx_desc		= rt2500pci_write_tx_desc,
 	.write_tx_desc		= rt2500pci_write_tx_desc,
 	.write_tx_data		= rt2x00pci_write_tx_data,
 	.write_tx_data		= rt2x00pci_write_tx_data,
+	.write_beacon		= rt2500pci_write_beacon,
 	.kick_tx_queue		= rt2500pci_kick_tx_queue,
 	.kick_tx_queue		= rt2500pci_kick_tx_queue,
 	.fill_rxdone		= rt2500pci_fill_rxdone,
 	.fill_rxdone		= rt2500pci_fill_rxdone,
 	.config_filter		= rt2500pci_config_filter,
 	.config_filter		= rt2500pci_config_filter,

+ 60 - 94
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);
 	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,
 static int rt2500usb_get_tx_data_len(struct rt2x00_dev *rt2x00dev,
 				     struct sk_buff *skb)
 				     struct sk_buff *skb)
 {
 {
@@ -1122,9 +1181,6 @@ static int rt2500usb_get_tx_data_len(struct rt2x00_dev *rt2x00dev,
 	return length;
 	return length;
 }
 }
 
 
-/*
- * TX data initialization
- */
 static void rt2500usb_kick_tx_queue(struct rt2x00_dev *rt2x00dev,
 static void rt2500usb_kick_tx_queue(struct rt2x00_dev *rt2x00dev,
 				    const enum data_queue_qid queue)
 				    const enum data_queue_qid queue)
 {
 {
@@ -1679,96 +1735,6 @@ static int rt2500usb_probe_hw(struct rt2x00_dev *rt2x00dev)
 	return 0;
 	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 = {
 static const struct ieee80211_ops rt2500usb_mac80211_ops = {
 	.tx			= rt2x00mac_tx,
 	.tx			= rt2x00mac_tx,
 	.start			= rt2x00mac_start,
 	.start			= rt2x00mac_start,
@@ -1782,7 +1748,6 @@ static const struct ieee80211_ops rt2500usb_mac80211_ops = {
 	.bss_info_changed	= rt2x00mac_bss_info_changed,
 	.bss_info_changed	= rt2x00mac_bss_info_changed,
 	.conf_tx		= rt2x00mac_conf_tx,
 	.conf_tx		= rt2x00mac_conf_tx,
 	.get_tx_stats		= rt2x00mac_get_tx_stats,
 	.get_tx_stats		= rt2x00mac_get_tx_stats,
-	.beacon_update		= rt2500usb_beacon_update,
 };
 };
 
 
 static const struct rt2x00lib_ops rt2500usb_rt2x00_ops = {
 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,
 	.link_tuner		= rt2500usb_link_tuner,
 	.write_tx_desc		= rt2500usb_write_tx_desc,
 	.write_tx_desc		= rt2500usb_write_tx_desc,
 	.write_tx_data		= rt2x00usb_write_tx_data,
 	.write_tx_data		= rt2x00usb_write_tx_data,
+	.write_beacon		= rt2500usb_write_beacon,
 	.get_tx_data_len	= rt2500usb_get_tx_data_len,
 	.get_tx_data_len	= rt2500usb_get_tx_data_len,
 	.kick_tx_queue		= rt2500usb_kick_tx_queue,
 	.kick_tx_queue		= rt2500usb_kick_tx_queue,
 	.fill_rxdone		= rt2500usb_fill_rxdone,
 	.fill_rxdone		= rt2500usb_fill_rxdone,

+ 4 - 33
drivers/net/wireless/rt2x00/rt2x00.h

@@ -364,6 +364,8 @@ struct rt2x00_intf {
 #define DELAYED_UPDATE_BEACON		0x00000001
 #define DELAYED_UPDATE_BEACON		0x00000001
 #define DELAYED_CONFIG_ERP		0x00000002
 #define DELAYED_CONFIG_ERP		0x00000002
 #define DELAYED_LED_ASSOC		0x00000004
 #define DELAYED_LED_ASSOC		0x00000004
+
+	u16 seqno;
 };
 };
 
 
 static inline struct rt2x00_intf* vif_to_intf(struct ieee80211_vif *vif)
 static inline struct rt2x00_intf* vif_to_intf(struct ieee80211_vif *vif)
@@ -434,6 +436,7 @@ struct rt2x00lib_conf {
  */
  */
 struct rt2x00lib_erp {
 struct rt2x00lib_erp {
 	int short_preamble;
 	int short_preamble;
+	int cts_protection;
 
 
 	int ack_timeout;
 	int ack_timeout;
 	int ack_consume_time;
 	int ack_consume_time;
@@ -520,6 +523,7 @@ struct rt2x00lib_ops {
 			       struct sk_buff *skb,
 			       struct sk_buff *skb,
 			       struct txentry_desc *txdesc);
 			       struct txentry_desc *txdesc);
 	int (*write_tx_data) (struct queue_entry *entry);
 	int (*write_tx_data) (struct queue_entry *entry);
+	void (*write_beacon) (struct queue_entry *entry);
 	int (*get_tx_data_len) (struct rt2x00_dev *rt2x00dev,
 	int (*get_tx_data_len) (struct rt2x00_dev *rt2x00dev,
 				struct sk_buff *skb);
 				struct sk_buff *skb);
 	void (*kick_tx_queue) (struct rt2x00_dev *rt2x00dev,
 	void (*kick_tx_queue) (struct rt2x00_dev *rt2x00dev,
@@ -909,39 +913,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);
 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
  * rt2x00queue_get_queue - Convert queue index to queue pointer
  * @rt2x00dev: Pointer to &struct rt2x00_dev.
  * @rt2x00dev: Pointer to &struct rt2x00_dev.

+ 2 - 0
drivers/net/wireless/rt2x00/rt2x00config.c

@@ -84,6 +84,8 @@ void rt2x00lib_config_erp(struct rt2x00_dev *rt2x00dev,
 	memset(&erp, 0, sizeof(erp));
 	memset(&erp, 0, sizeof(erp));
 
 
 	erp.short_preamble = bss_conf->use_short_preamble;
 	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_timeout = PLCP + get_duration(ACK_SIZE, 10);
 	erp.ack_consume_time = SIFS + PLCP + get_duration(ACK_SIZE, 10);
 	erp.ack_consume_time = SIFS + PLCP + get_duration(ACK_SIZE, 10);
 
 

+ 2 - 7
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_dev *rt2x00dev = data;
 	struct rt2x00_intf *intf = vif_to_intf(vif);
 	struct rt2x00_intf *intf = vif_to_intf(vif);
-	struct sk_buff *skb;
 	struct ieee80211_bss_conf conf;
 	struct ieee80211_bss_conf conf;
 	int delayed_flags;
 	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))
 	if (!test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags))
 		return;
 		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)
 	if (delayed_flags & DELAYED_CONFIG_ERP)
 		rt2x00lib_config_erp(rt2x00dev, intf, &conf);
 		rt2x00lib_config_erp(rt2x00dev, intf, &conf);

+ 8 - 0
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,
 	retval = rt2x00dev->ops->lib->load_firmware(rt2x00dev,
 						    rt2x00dev->fw->data,
 						    rt2x00dev->fw->data,
 						    rt2x00dev->fw->size);
 						    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;
 	return retval;
 }
 }
 
 

+ 8 - 0
drivers/net/wireless/rt2x00/rt2x00lib.h

@@ -138,6 +138,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);
 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
  * rt2x00queue_index_inc - Index incrementation function
  * @queue: Queue (&struct data_queue) to perform the action on.
  * @queue: Queue (&struct data_queue) to perform the action on.

+ 26 - 14
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_tx_info *tx_info = IEEE80211_SKB_CB(skb);
 	struct ieee80211_hdr *ieee80211hdr = (struct ieee80211_hdr *)skb->data;
 	struct ieee80211_hdr *ieee80211hdr = (struct ieee80211_hdr *)skb->data;
 	enum data_queue_qid qid = skb_get_queue_mapping(skb);
 	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;
 	struct data_queue *queue;
 	u16 frame_control;
 	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)) {
 	if (rt2x00queue_write_tx_frame(queue, skb)) {
 		ieee80211_stop_queue(rt2x00dev->hw, qid);
 		ieee80211_stop_queue(rt2x00dev->hw, qid);
 		return NETDEV_TX_BUSY;
 		return NETDEV_TX_BUSY;
@@ -348,7 +361,8 @@ int rt2x00mac_config_interface(struct ieee80211_hw *hw,
 {
 {
 	struct rt2x00_dev *rt2x00dev = hw->priv;
 	struct rt2x00_dev *rt2x00dev = hw->priv;
 	struct rt2x00_intf *intf = vif_to_intf(vif);
 	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
 	 * 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);
 	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);
 		memcpy(&intf->bssid, conf->bssid, ETH_ALEN);
+	}
 
 
 	spin_unlock(&intf->lock);
 	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
 	 * values as arguments we make keep access to rt2x00_intf thread safe
 	 * even without the lock.
 	 * 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;
 	return status;
 }
 }
@@ -501,7 +513,7 @@ void rt2x00mac_bss_info_changed(struct ieee80211_hw *hw,
 	 * When the erp information has changed, we should perform
 	 * When the erp information has changed, we should perform
 	 * additional configuration steps. For all other changes we are done.
 	 * 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))
 		if (!test_bit(DRIVER_REQUIRE_SCHEDULED, &rt2x00dev->flags))
 			rt2x00lib_config_erp(rt2x00dev, intf, bss_conf);
 			rt2x00lib_config_erp(rt2x00dev, intf, bss_conf);
 		else
 		else

+ 61 - 6
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)
 void rt2x00queue_free_skb(struct rt2x00_dev *rt2x00dev, struct sk_buff *skb)
 {
 {
+	if (!skb)
+		return;
+
 	rt2x00queue_unmap_skb(rt2x00dev, skb);
 	rt2x00queue_unmap_skb(rt2x00dev, skb);
 	dev_kfree_skb_any(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 rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
 	struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(entry->skb);
 	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;
 			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 data_queue *queue = entry->queue;
 	struct rt2x00_dev *rt2x00dev = queue->rt2x00dev;
 	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))
 	    !test_bit(ENTRY_TXD_BURST, &txdesc->flags))
 		rt2x00dev->ops->lib->kick_tx_queue(rt2x00dev, queue->qid);
 		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)
 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;
 	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,
 struct data_queue *rt2x00queue_get_queue(struct rt2x00_dev *rt2x00dev,
 					 const enum data_queue_qid queue)
 					 const enum data_queue_qid queue)
 {
 {

+ 36 - 67
drivers/net/wireless/rt2x00/rt61pci.c

@@ -1600,6 +1600,41 @@ static void rt61pci_write_tx_desc(struct rt2x00_dev *rt2x00dev,
 /*
 /*
  * TX data initialization
  * 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,
 static void rt61pci_kick_tx_queue(struct rt2x00_dev *rt2x00dev,
 				  const enum data_queue_qid queue)
 				  const enum data_queue_qid queue)
 {
 {
@@ -2355,72 +2390,6 @@ static u64 rt61pci_get_tsf(struct ieee80211_hw *hw)
 	return tsf;
 	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 = {
 static const struct ieee80211_ops rt61pci_mac80211_ops = {
 	.tx			= rt2x00mac_tx,
 	.tx			= rt2x00mac_tx,
 	.start			= rt2x00mac_start,
 	.start			= rt2x00mac_start,
@@ -2436,7 +2405,6 @@ static const struct ieee80211_ops rt61pci_mac80211_ops = {
 	.conf_tx		= rt2x00mac_conf_tx,
 	.conf_tx		= rt2x00mac_conf_tx,
 	.get_tx_stats		= rt2x00mac_get_tx_stats,
 	.get_tx_stats		= rt2x00mac_get_tx_stats,
 	.get_tsf		= rt61pci_get_tsf,
 	.get_tsf		= rt61pci_get_tsf,
-	.beacon_update		= rt61pci_beacon_update,
 };
 };
 
 
 static const struct rt2x00lib_ops rt61pci_rt2x00_ops = {
 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,
 	.link_tuner		= rt61pci_link_tuner,
 	.write_tx_desc		= rt61pci_write_tx_desc,
 	.write_tx_desc		= rt61pci_write_tx_desc,
 	.write_tx_data		= rt2x00pci_write_tx_data,
 	.write_tx_data		= rt2x00pci_write_tx_data,
+	.write_beacon		= rt61pci_write_beacon,
 	.kick_tx_queue		= rt61pci_kick_tx_queue,
 	.kick_tx_queue		= rt61pci_kick_tx_queue,
 	.fill_rxdone		= rt61pci_fill_rxdone,
 	.fill_rxdone		= rt61pci_fill_rxdone,
 	.config_filter		= rt61pci_config_filter,
 	.config_filter		= rt61pci_config_filter,

+ 44 - 71
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);
 	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,
 static int rt73usb_get_tx_data_len(struct rt2x00_dev *rt2x00dev,
 				   struct sk_buff *skb)
 				   struct sk_buff *skb)
 {
 {
@@ -1358,9 +1401,6 @@ static int rt73usb_get_tx_data_len(struct rt2x00_dev *rt2x00dev,
 	return length;
 	return length;
 }
 }
 
 
-/*
- * TX data initialization
- */
 static void rt73usb_kick_tx_queue(struct rt2x00_dev *rt2x00dev,
 static void rt73usb_kick_tx_queue(struct rt2x00_dev *rt2x00dev,
 				  const enum data_queue_qid queue)
 				  const enum data_queue_qid queue)
 {
 {
@@ -1958,73 +1998,6 @@ static u64 rt73usb_get_tsf(struct ieee80211_hw *hw)
 #define rt73usb_get_tsf	NULL
 #define rt73usb_get_tsf	NULL
 #endif
 #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 = {
 static const struct ieee80211_ops rt73usb_mac80211_ops = {
 	.tx			= rt2x00mac_tx,
 	.tx			= rt2x00mac_tx,
 	.start			= rt2x00mac_start,
 	.start			= rt2x00mac_start,
@@ -2040,7 +2013,6 @@ static const struct ieee80211_ops rt73usb_mac80211_ops = {
 	.conf_tx		= rt2x00mac_conf_tx,
 	.conf_tx		= rt2x00mac_conf_tx,
 	.get_tx_stats		= rt2x00mac_get_tx_stats,
 	.get_tx_stats		= rt2x00mac_get_tx_stats,
 	.get_tsf		= rt73usb_get_tsf,
 	.get_tsf		= rt73usb_get_tsf,
-	.beacon_update		= rt73usb_beacon_update,
 };
 };
 
 
 static const struct rt2x00lib_ops rt73usb_rt2x00_ops = {
 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,
 	.link_tuner		= rt73usb_link_tuner,
 	.write_tx_desc		= rt73usb_write_tx_desc,
 	.write_tx_desc		= rt73usb_write_tx_desc,
 	.write_tx_data		= rt2x00usb_write_tx_data,
 	.write_tx_data		= rt2x00usb_write_tx_data,
+	.write_beacon		= rt73usb_write_beacon,
 	.get_tx_data_len	= rt73usb_get_tx_data_len,
 	.get_tx_data_len	= rt73usb_get_tx_data_len,
 	.kick_tx_queue		= rt73usb_kick_tx_queue,
 	.kick_tx_queue		= rt73usb_kick_tx_queue,
 	.fill_rxdone		= rt73usb_fill_rxdone,
 	.fill_rxdone		= rt73usb_fill_rxdone,

+ 15 - 8
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);
 	reg = rtl818x_ioread8(priv, &priv->map->CONFIG3);
 	rtl818x_iowrite8(priv, &priv->map->CONFIG3, reg |
 	rtl818x_iowrite8(priv, &priv->map->CONFIG3, reg |
 			 RTL818X_CONFIG3_ANAPARAM_WRITE);
 			 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_iowrite8(priv, &priv->map->CONFIG3, reg &
 			 ~RTL818X_CONFIG3_ANAPARAM_WRITE);
 			 ~RTL818X_CONFIG3_ANAPARAM_WRITE);
 	rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD,
 	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);
 	reg = rtl818x_ioread8(priv, &priv->map->CONFIG3);
 	rtl818x_iowrite8(priv, &priv->map->CONFIG3,
 	rtl818x_iowrite8(priv, &priv->map->CONFIG3,
 			reg | RTL818X_CONFIG3_ANAPARAM_WRITE);
 			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,
 	rtl818x_iowrite8(priv, &priv->map->CONFIG3,
 			reg & ~RTL818X_CONFIG3_ANAPARAM_WRITE);
 			reg & ~RTL818X_CONFIG3_ANAPARAM_WRITE);
 	rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL);
 	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_ioread8(priv, &priv->map->CONFIG3);
 	reg |= RTL818X_CONFIG3_ANAPARAM_WRITE | RTL818X_CONFIG3_GNT_SELECT;
 	reg |= RTL818X_CONFIG3_ANAPARAM_WRITE | RTL818X_CONFIG3_GNT_SELECT;
 	rtl818x_iowrite8(priv, &priv->map->CONFIG3, reg);
 	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);
 	rtl818x_iowrite8(priv, (u8 *)0xFF61, 0x10);
 	reg = rtl818x_ioread8(priv, (u8 *)0xFF62);
 	reg = rtl818x_ioread8(priv, (u8 *)0xFF62);
@@ -1180,7 +1187,7 @@ static struct usb_driver rtl8187_driver = {
 	.name		= KBUILD_MODNAME,
 	.name		= KBUILD_MODNAME,
 	.id_table	= rtl8187_table,
 	.id_table	= rtl8187_table,
 	.probe		= rtl8187_probe,
 	.probe		= rtl8187_probe,
-	.disconnect	= rtl8187_disconnect,
+	.disconnect	= __devexit_p(rtl8187_disconnect),
 };
 };
 
 
 static int __init rtl8187_init(void)
 static int __init rtl8187_init(void)

+ 17 - 4
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);
 	reg = rtl818x_ioread8(priv, &priv->map->CONFIG3);
 	rtl818x_iowrite8(priv, &priv->map->CONFIG3,
 	rtl818x_iowrite8(priv, &priv->map->CONFIG3,
 			reg | RTL818X_CONFIG3_ANAPARAM_WRITE);
 			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,
 	rtl818x_iowrite8(priv, &priv->map->CONFIG3,
 			reg & ~RTL818X_CONFIG3_ANAPARAM_WRITE);
 			reg & ~RTL818X_CONFIG3_ANAPARAM_WRITE);
 	rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL);
 	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);
 	reg = rtl818x_ioread8(priv, &priv->map->CONFIG3);
 	rtl818x_iowrite8(priv, &priv->map->CONFIG3,
 	rtl818x_iowrite8(priv, &priv->map->CONFIG3,
 			reg | RTL818X_CONFIG3_ANAPARAM_WRITE);
 			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,
 	rtl818x_iowrite8(priv, &priv->map->CONFIG3,
 			reg & ~RTL818X_CONFIG3_ANAPARAM_WRITE);
 			reg & ~RTL818X_CONFIG3_ANAPARAM_WRITE);
 	rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL);
 	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);
 	rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG);
 	reg = rtl818x_ioread8(priv, &priv->map->CONFIG3);
 	reg = rtl818x_ioread8(priv, &priv->map->CONFIG3);
 	rtl818x_iowrite8(priv, &priv->map->CONFIG3, reg | RTL818X_CONFIG3_ANAPARAM_WRITE);
 	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->CONFIG3, reg & ~RTL818X_CONFIG3_ANAPARAM_WRITE);
 	rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL);
 	rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL);
 }
 }

+ 11 - 4
drivers/net/wireless/rtl8187_rtl8225.h

@@ -15,10 +15,17 @@
 #ifndef RTL8187_RTL8225_H
 #ifndef RTL8187_RTL8225_H
 #define 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 *);
 const struct rtl818x_rf_ops * rtl8187_detect_rf(struct ieee80211_hw *);
 
 

+ 7 - 15
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 ||
 	if (mac->type == IEEE80211_IF_TYPE_MESH_POINT ||
 	    mac->type == IEEE80211_IF_TYPE_IBSS) {
 	    mac->type == IEEE80211_IF_TYPE_IBSS) {
 		associated = true;
 		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)
 			if (r < 0)
 				return r;
 				return r;
 			r = zd_set_beacon_interval(&mac->chip, BCN_MODE_IBSS |
 			r = zd_set_beacon_interval(&mac->chip, BCN_MODE_IBSS |
 					hw->conf.beacon_int);
 					hw->conf.beacon_int);
 			if (r < 0)
 			if (r < 0)
 				return r;
 				return r;
-			kfree_skb(conf->beacon);
+			kfree_skb(beacon);
 		}
 		}
 	} else
 	} else
 		associated = is_valid_ether_addr(conf->bssid);
 		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 = {
 static const struct ieee80211_ops zd_ops = {
 	.tx			= zd_op_tx,
 	.tx			= zd_op_tx,
 	.start			= zd_op_start,
 	.start			= zd_op_start,
@@ -911,7 +904,6 @@ static const struct ieee80211_ops zd_ops = {
 	.config_interface	= zd_op_config_interface,
 	.config_interface	= zd_op_config_interface,
 	.configure_filter	= zd_op_configure_filter,
 	.configure_filter	= zd_op_configure_filter,
 	.bss_info_changed	= zd_op_bss_info_changed,
 	.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)
 struct ieee80211_hw *zd_mac_alloc_hw(struct usb_interface *intf)

+ 1 - 0
include/linux/ssb/ssb.h

@@ -7,6 +7,7 @@
 #include <linux/spinlock.h>
 #include <linux/spinlock.h>
 #include <linux/pci.h>
 #include <linux/pci.h>
 #include <linux/mod_devicetable.h>
 #include <linux/mod_devicetable.h>
+#include <linux/dma-mapping.h>
 
 
 #include <linux/ssb/ssb_regs.h>
 #include <linux/ssb/ssb_regs.h>
 
 

+ 35 - 38
include/net/mac80211.h

@@ -115,17 +115,17 @@ enum ieee80211_max_queues {
  * The information provided in this structure is required for QoS
  * The information provided in this structure is required for QoS
  * transmit queue configuration. Cf. IEEE 802.11 7.3.2.29.
  * 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]
  * @cw_max: maximum contention window [like @cw_min]
  * @txop: maximum burst time in units of 32 usecs, 0 meaning disabled
  * @txop: maximum burst time in units of 32 usecs, 0 meaning disabled
  */
  */
 struct ieee80211_tx_queue_params {
 struct ieee80211_tx_queue_params {
-	s16 aifs;
+	u16 txop;
 	u16 cw_min;
 	u16 cw_min;
 	u16 cw_max;
 	u16 cw_max;
-	u16 txop;
+	u8 aifs;
 };
 };
 
 
 /**
 /**
@@ -239,6 +239,17 @@ struct ieee80211_bss_conf {
  * 	is for the whole aggregation.
  * 	is for the whole aggregation.
  * @IEEE80211_TX_STAT_AMPDU_NO_BACK: no block ack was returned,
  * @IEEE80211_TX_STAT_AMPDU_NO_BACK: no block ack was returned,
  * 	so consider using block ack request (BAR).
  * 	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 {
 enum mac80211_tx_control_flags {
 	IEEE80211_TX_CTL_REQ_TX_STATUS		= BIT(0),
 	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_ACK			= BIT(21),
 	IEEE80211_TX_STAT_AMPDU			= BIT(22),
 	IEEE80211_TX_STAT_AMPDU			= BIT(22),
 	IEEE80211_TX_STAT_AMPDU_NO_BACK		= BIT(23),
 	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_SHORT_SLOT_TIME: use 802.11g short slot time
  * @IEEE80211_CONF_RADIOTAP: add radiotap header at receive time (if supported)
  * @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_SUPPORT_HT_MODE: use 802.11n HT capabilities (if supported)
+ * @IEEE80211_CONF_PS: Enable 802.11 power save mode
  */
  */
 enum ieee80211_conf_flags {
 enum ieee80211_conf_flags {
 	IEEE80211_CONF_SHORT_SLOT_TIME	= (1<<0),
 	IEEE80211_CONF_SHORT_SLOT_TIME	= (1<<0),
 	IEEE80211_CONF_RADIOTAP		= (1<<1),
 	IEEE80211_CONF_RADIOTAP		= (1<<1),
 	IEEE80211_CONF_SUPPORT_HT_MODE	= (1<<2),
 	IEEE80211_CONF_SUPPORT_HT_MODE	= (1<<2),
+	IEEE80211_CONF_PS		= (1<<3),
 };
 };
 
 
 /**
 /**
@@ -526,34 +540,39 @@ struct ieee80211_if_init_conf {
 	void *mac_addr;
 	void *mac_addr;
 };
 };
 
 
+/**
+ * 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
  * 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.
  * @bssid: BSSID of the network we are associated to/creating.
  * @ssid: used (together with @ssid_len) by drivers for hardware that
  * @ssid: used (together with @ssid_len) by drivers for hardware that
  *	generate beacons independently. The pointer is valid only during the
  *	generate beacons independently. The pointer is valid only during the
  *	config_interface() call, so copy the value somewhere if you need
  *	config_interface() call, so copy the value somewhere if you need
  *	it.
  *	it.
  * @ssid_len: length of the @ssid field.
  * @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
  * This structure is passed to the config_interface() callback of
  * &struct ieee80211_hw.
  * &struct ieee80211_hw.
  */
  */
 struct ieee80211_if_conf {
 struct ieee80211_if_conf {
-	int type;
+	u32 changed;
 	u8 *bssid;
 	u8 *bssid;
 	u8 *ssid;
 	u8 *ssid;
 	size_t ssid_len;
 	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,
  * any particular flags. There are some exceptions to this rule,
  * however, so you are advised to review these flags carefully.
  * 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:
  * @IEEE80211_HW_RX_INCLUDES_FCS:
  *	Indicates that received frames passed to the stack include
  *	Indicates that received frames passed to the stack include
  *	the FCS at the end.
  *	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
  *	function is optional if the firmware/hardware takes full care of
  *	TSF synchronization.
  *	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.
  * @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
  *	This is needed only for IBSS mode and the result of this function is
  *	used to determine whether to reply to Probe Requests.
  *	used to determine whether to reply to Probe Requests.
@@ -1217,8 +1216,6 @@ struct ieee80211_ops {
 			    struct ieee80211_tx_queue_stats *stats);
 			    struct ieee80211_tx_queue_stats *stats);
 	u64 (*get_tsf)(struct ieee80211_hw *hw);
 	u64 (*get_tsf)(struct ieee80211_hw *hw);
 	void (*reset_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 (*tx_last_beacon)(struct ieee80211_hw *hw);
 	int (*ampdu_action)(struct ieee80211_hw *hw,
 	int (*ampdu_action)(struct ieee80211_hw *hw,
 			    enum ieee80211_ampdu_mlme_action action,
 			    enum ieee80211_ampdu_mlme_action action,

+ 2 - 2
net/core/net-sysfs.c

@@ -318,7 +318,7 @@ static struct attribute_group netstat_group = {
 	.attrs  = netstat_attrs,
 	.attrs  = netstat_attrs,
 };
 };
 
 
-#ifdef CONFIG_WIRELESS_EXT
+#ifdef CONFIG_WIRELESS_EXT_SYSFS
 /* helper function that does all the locking etc for wireless stats */
 /* helper function that does all the locking etc for wireless stats */
 static ssize_t wireless_show(struct device *d, char *buf,
 static ssize_t wireless_show(struct device *d, char *buf,
 			     ssize_t (*format)(const struct iw_statistics *,
 			     ssize_t (*format)(const struct iw_statistics *,
@@ -459,7 +459,7 @@ int netdev_register_kobject(struct net_device *net)
 #ifdef CONFIG_SYSFS
 #ifdef CONFIG_SYSFS
 	*groups++ = &netstat_group;
 	*groups++ = &netstat_group;
 
 
-#ifdef CONFIG_WIRELESS_EXT
+#ifdef CONFIG_WIRELESS_EXT_SYSFS
 	if (net->wireless_handlers && net->wireless_handlers->get_wireless_stats)
 	if (net->wireless_handlers && net->wireless_handlers->get_wireless_stats)
 		*groups++ = &wireless_group;
 		*groups++ = &wireless_group;
 #endif
 #endif

+ 10 - 26
net/mac80211/cfg.c

@@ -50,14 +50,11 @@ static int ieee80211_add_iface(struct wiphy *wiphy, char *name,
 	struct ieee80211_sub_if_data *sdata;
 	struct ieee80211_sub_if_data *sdata;
 	int err;
 	int err;
 
 
-	if (unlikely(local->reg_state != IEEE80211_DEV_REGISTERED))
-		return -ENODEV;
-
 	itype = nl80211_type_to_mac80211_type(type);
 	itype = nl80211_type_to_mac80211_type(type);
 	if (itype == IEEE80211_IF_TYPE_INVALID)
 	if (itype == IEEE80211_IF_TYPE_INVALID)
 		return -EINVAL;
 		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)
 	if (err || itype != IEEE80211_IF_TYPE_MNTR || !flags)
 		return err;
 		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)
 static int ieee80211_del_iface(struct wiphy *wiphy, int ifindex)
 {
 {
-	struct ieee80211_local *local = wiphy_priv(wiphy);
 	struct net_device *dev;
 	struct net_device *dev;
-	char *name;
-
-	if (unlikely(local->reg_state != IEEE80211_DEV_REGISTERED))
-		return -ENODEV;
 
 
 	/* we're under RTNL */
 	/* we're under RTNL */
 	dev = __dev_get_by_index(&init_net, ifindex);
 	dev = __dev_get_by_index(&init_net, ifindex);
 	if (!dev)
 	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,
 static int ieee80211_change_iface(struct wiphy *wiphy, int ifindex,
 				  enum nl80211_iftype type, u32 *flags,
 				  enum nl80211_iftype type, u32 *flags,
 				  struct vif_params *params)
 				  struct vif_params *params)
 {
 {
-	struct ieee80211_local *local = wiphy_priv(wiphy);
 	struct net_device *dev;
 	struct net_device *dev;
 	enum ieee80211_if_types itype;
 	enum ieee80211_if_types itype;
 	struct ieee80211_sub_if_data *sdata;
 	struct ieee80211_sub_if_data *sdata;
-
-	if (unlikely(local->reg_state != IEEE80211_DEV_REGISTERED))
-		return -ENODEV;
+	int ret;
 
 
 	/* we're under RTNL */
 	/* we're under RTNL */
 	dev = __dev_get_by_index(&init_net, ifindex);
 	dev = __dev_get_by_index(&init_net, ifindex);
 	if (!dev)
 	if (!dev)
 		return -ENODEV;
 		return -ENODEV;
 
 
-	if (netif_running(dev))
-		return -EBUSY;
-
 	itype = nl80211_type_to_mac80211_type(type);
 	itype = nl80211_type_to_mac80211_type(type);
 	if (itype == IEEE80211_IF_TYPE_INVALID)
 	if (itype == IEEE80211_IF_TYPE_INVALID)
 		return -EINVAL;
 		return -EINVAL;
 
 
 	sdata = IEEE80211_DEV_TO_SUB_IF(dev);
 	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)
 	if (ieee80211_vif_is_mesh(&sdata->vif) && params->mesh_id_len)
 		ieee80211_if_sta_set_mesh_id(&sdata->u.sta,
 		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);
 	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,
 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();
 	synchronize_rcu();
 	kfree(old);
 	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) */
 /* Layer 2 Update frame (802.2 Type 1 LLC XID Update response) */

+ 1 - 14
net/mac80211/debugfs.c

@@ -70,16 +70,6 @@ DEBUGFS_READONLY_FILE(rate_ctrl_alg, 100, "%s",
 
 
 /* statistics stuff */
 /* 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...)			\
 #define DEBUGFS_STATS_FILE(name, buflen, fmt, value...)			\
 	DEBUGFS_READONLY_FILE(stats_ ##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)
 	if (!local->ops->get_stats)
 		return -EOPNOTSUPP;
 		return -EOPNOTSUPP;
 
 
-	res = rtnl_lock_local(local);
-	if (res)
-		return res;
-
+	rtnl_lock();
 	res = local->ops->get_stats(local_to_hw(local), &stats);
 	res = local->ops->get_stats(local_to_hw(local), &stats);
 	rtnl_unlock();
 	rtnl_unlock();
 	if (!res)
 	if (!res)

+ 31 - 17
net/mac80211/debugfs_netdev.c

@@ -156,6 +156,8 @@ static const struct file_operations name##_ops = {			\
 
 
 /* common attributes */
 /* common attributes */
 IEEE80211_IF_FILE(drop_unencrypted, drop_unencrypted, DEC);
 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 */
 /* STA/IBSS attributes */
 IEEE80211_IF_FILE(state, u.sta.state, DEC);
 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(num_sta_ps, u.ap.num_sta_ps, ATOMIC);
 IEEE80211_IF_FILE(dtim_count, u.ap.dtim_count, DEC);
 IEEE80211_IF_FILE(dtim_count, u.ap.dtim_count, DEC);
 IEEE80211_IF_FILE(num_beacons, u.ap.num_beacons, 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(
 static ssize_t ieee80211_if_fmt_num_buffered_multicast(
 	const struct ieee80211_sub_if_data *sdata, char *buf, int buflen)
 	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)
 static void add_sta_files(struct ieee80211_sub_if_data *sdata)
 {
 {
 	DEBUGFS_ADD(drop_unencrypted, sta);
 	DEBUGFS_ADD(drop_unencrypted, sta);
+	DEBUGFS_ADD(force_unicast_rateidx, ap);
+	DEBUGFS_ADD(max_ratectrl_rateidx, ap);
+
 	DEBUGFS_ADD(state, sta);
 	DEBUGFS_ADD(state, sta);
 	DEBUGFS_ADD(bssid, sta);
 	DEBUGFS_ADD(bssid, sta);
 	DEBUGFS_ADD(prev_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)
 static void add_ap_files(struct ieee80211_sub_if_data *sdata)
 {
 {
 	DEBUGFS_ADD(drop_unencrypted, ap);
 	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(num_sta_ps, ap);
 	DEBUGFS_ADD(dtim_count, ap);
 	DEBUGFS_ADD(dtim_count, ap);
 	DEBUGFS_ADD(num_beacons, ap);
 	DEBUGFS_ADD(num_beacons, ap);
-	DEBUGFS_ADD(force_unicast_rateidx, ap);
-	DEBUGFS_ADD(max_ratectrl_rateidx, ap);
 	DEBUGFS_ADD(num_buffered_multicast, ap);
 	DEBUGFS_ADD(num_buffered_multicast, ap);
 }
 }
 
 
 static void add_wds_files(struct ieee80211_sub_if_data *sdata)
 static void add_wds_files(struct ieee80211_sub_if_data *sdata)
 {
 {
 	DEBUGFS_ADD(drop_unencrypted, wds);
 	DEBUGFS_ADD(drop_unencrypted, wds);
+	DEBUGFS_ADD(force_unicast_rateidx, ap);
+	DEBUGFS_ADD(max_ratectrl_rateidx, ap);
+
 	DEBUGFS_ADD(peer, wds);
 	DEBUGFS_ADD(peer, wds);
 }
 }
 
 
 static void add_vlan_files(struct ieee80211_sub_if_data *sdata)
 static void add_vlan_files(struct ieee80211_sub_if_data *sdata)
 {
 {
 	DEBUGFS_ADD(drop_unencrypted, vlan);
 	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)
 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)
 static void del_sta_files(struct ieee80211_sub_if_data *sdata)
 {
 {
 	DEBUGFS_DEL(drop_unencrypted, sta);
 	DEBUGFS_DEL(drop_unencrypted, sta);
+	DEBUGFS_DEL(force_unicast_rateidx, ap);
+	DEBUGFS_DEL(max_ratectrl_rateidx, ap);
+
 	DEBUGFS_DEL(state, sta);
 	DEBUGFS_DEL(state, sta);
 	DEBUGFS_DEL(bssid, sta);
 	DEBUGFS_DEL(bssid, sta);
 	DEBUGFS_DEL(prev_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)
 static void del_ap_files(struct ieee80211_sub_if_data *sdata)
 {
 {
 	DEBUGFS_DEL(drop_unencrypted, ap);
 	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(num_sta_ps, ap);
 	DEBUGFS_DEL(dtim_count, ap);
 	DEBUGFS_DEL(dtim_count, ap);
 	DEBUGFS_DEL(num_beacons, ap);
 	DEBUGFS_DEL(num_beacons, ap);
-	DEBUGFS_DEL(force_unicast_rateidx, ap);
-	DEBUGFS_DEL(max_ratectrl_rateidx, ap);
 	DEBUGFS_DEL(num_buffered_multicast, ap);
 	DEBUGFS_DEL(num_buffered_multicast, ap);
 }
 }
 
 
 static void del_wds_files(struct ieee80211_sub_if_data *sdata)
 static void del_wds_files(struct ieee80211_sub_if_data *sdata)
 {
 {
 	DEBUGFS_DEL(drop_unencrypted, wds);
 	DEBUGFS_DEL(drop_unencrypted, wds);
+	DEBUGFS_DEL(force_unicast_rateidx, ap);
+	DEBUGFS_DEL(max_ratectrl_rateidx, ap);
+
 	DEBUGFS_DEL(peer, wds);
 	DEBUGFS_DEL(peer, wds);
 }
 }
 
 
 static void del_vlan_files(struct ieee80211_sub_if_data *sdata)
 static void del_vlan_files(struct ieee80211_sub_if_data *sdata)
 {
 {
 	DEBUGFS_DEL(drop_unencrypted, vlan);
 	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)
 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
 #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)
 	if (!sdata->debugfsdir)
 		return;
 		return;
 
 
-	switch (type) {
+	switch (sdata->vif.type) {
 	case IEEE80211_IF_TYPE_MESH_POINT:
 	case IEEE80211_IF_TYPE_MESH_POINT:
 #ifdef CONFIG_MAC80211_MESH
 #ifdef CONFIG_MAC80211_MESH
 		del_mesh_stats(sdata);
 		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);
 	sprintf(buf, "netdev:%s", sdata->dev->name);
 	sdata->debugfsdir = debugfs_create_dir(buf,
 	sdata->debugfsdir = debugfs_create_dir(buf,
 		sdata->local->hw.wiphy->debugfsdir);
 		sdata->local->hw.wiphy->debugfsdir);
+	add_files(sdata);
 }
 }
 
 
 void ieee80211_debugfs_remove_netdev(struct ieee80211_sub_if_data *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);
 	debugfs_remove(sdata->debugfsdir);
 	sdata->debugfsdir = NULL;
 	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,
 static int netdev_notify(struct notifier_block *nb,
 			 unsigned long state,
 			 unsigned long state,
 			 void *ndev)
 			 void *ndev)
 {
 {
 	struct net_device *dev = ndev;
 	struct net_device *dev = ndev;
 	struct dentry *dir;
 	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];
 	char buf[10+IFNAMSIZ];
 
 
 	if (state != NETDEV_CHANGENAME)
 	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)
 	if (dev->ieee80211_ptr->wiphy->privid != mac80211_wiphy_privid)
 		return 0;
 		return 0;
 
 
+	sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+
 	sprintf(buf, "netdev:%s", dev->name);
 	sprintf(buf, "netdev:%s", dev->name);
 	dir = sdata->debugfsdir;
 	dir = sdata->debugfsdir;
 	if (!debugfs_rename(dir->d_parent, dir, dir->d_parent, buf))
 	if (!debugfs_rename(dir->d_parent, dir, dir->d_parent, buf))

+ 0 - 5
net/mac80211/debugfs_netdev.h

@@ -6,8 +6,6 @@
 #ifdef CONFIG_MAC80211_DEBUGFS
 #ifdef CONFIG_MAC80211_DEBUGFS
 void ieee80211_debugfs_add_netdev(struct ieee80211_sub_if_data *sdata);
 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_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_init(void);
 void ieee80211_debugfs_netdev_exit(void);
 void ieee80211_debugfs_netdev_exit(void);
 #else
 #else
@@ -17,9 +15,6 @@ static inline void ieee80211_debugfs_add_netdev(
 static inline void ieee80211_debugfs_remove_netdev(
 static inline void ieee80211_debugfs_remove_netdev(
 	struct ieee80211_sub_if_data *sdata)
 	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)
 static inline void ieee80211_debugfs_netdev_init(void)
 {}
 {}
 
 

+ 31 - 36
net/mac80211/ieee80211_i.h

@@ -237,8 +237,6 @@ struct ieee80211_if_ap {
 	struct sk_buff_head ps_bc_buf;
 	struct sk_buff_head ps_bc_buf;
 	atomic_t num_sta_ps; /* number of stations in PS mode */
 	atomic_t num_sta_ps; /* number of stations in PS mode */
 	int dtim_count;
 	int dtim_count;
-	int force_unicast_rateidx; /* forced TX rateidx for unicast frames */
-	int max_ratectrl_rateidx; /* max TX rateidx for rate control */
 	int num_beacons; /* number of TXed beacon frames for this BSS */
 	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_if_vlan {
-	struct ieee80211_sub_if_data *ap;
 	struct list_head list;
 	struct list_head list;
 };
 };
 
 
@@ -422,8 +419,6 @@ struct ieee80211_sub_if_data {
 	 */
 	 */
 	u64 basic_rates;
 	u64 basic_rates;
 
 
-	u16 sequence;
-
 	/* Fragment table for host-based reassembly */
 	/* Fragment table for host-based reassembly */
 	struct ieee80211_fragment_entry	fragments[IEEE80211_FRAGMENT_MAX];
 	struct ieee80211_fragment_entry	fragments[IEEE80211_FRAGMENT_MAX];
 	unsigned int fragment_next;
 	unsigned int fragment_next;
@@ -432,16 +427,18 @@ struct ieee80211_sub_if_data {
 	struct ieee80211_key *keys[NUM_DEFAULT_KEYS];
 	struct ieee80211_key *keys[NUM_DEFAULT_KEYS];
 	struct ieee80211_key *default_key;
 	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 {
 	union {
 		struct ieee80211_if_ap ap;
 		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);
 	return container_of(p, struct ieee80211_sub_if_data, vif);
 }
 }
 
 
-#define IEEE80211_DEV_TO_SUB_IF(dev) netdev_priv(dev)
-
 enum {
 enum {
 	IEEE80211_RX_MSG	= 1,
 	IEEE80211_RX_MSG	= 1,
 	IEEE80211_TX_STATUS_MSG	= 2,
 	IEEE80211_TX_STATUS_MSG	= 2,
@@ -561,12 +556,6 @@ struct ieee80211_local {
 	bool tim_in_locked_section; /* see ieee80211_beacon_get() */
 	bool tim_in_locked_section; /* see ieee80211_beacon_get() */
 	int tx_headroom; /* required headroom for hardware/radiotap */
 	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
 	/* Tasklet and skb queue to process calls from IRQ mode. All frames
 	 * added to skb_queue will be processed, but frames in
 	 * added to skb_queue will be processed, but frames in
 	 * skb_queue_unreliable may be dropped if the total length of these
 	 * 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
 #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 */
 /* this struct represents 802.11n's RA/TID combination */
 struct ieee80211_ra_tid {
 struct ieee80211_ra_tid {
 	u8 ra[ETH_ALEN];
 	u8 ra[ETH_ALEN];
@@ -853,10 +852,8 @@ static inline int ieee80211_bssid_match(const u8 *raddr, const u8 *addr)
 
 
 /* ieee80211.c */
 /* ieee80211.c */
 int ieee80211_hw_config(struct ieee80211_local *local);
 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_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,
 u32 ieee80211_handle_ht(struct ieee80211_local *local, int enable_ht,
 			struct ieee80211_ht_info *req_ht_cap,
 			struct ieee80211_ht_info *req_ht_cap,
 			struct ieee80211_ht_bss_info *req_bss_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(
 ieee80211_rx_result ieee80211_sta_rx_scan(
 	struct net_device *dev, struct sk_buff *skb,
 	struct net_device *dev, struct sk_buff *skb,
 	struct ieee80211_rx_status *rx_status);
 	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);
 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 sta_info *ieee80211_ibss_add_sta(struct net_device *dev,
 					struct sk_buff *skb, u8 *bssid,
 					struct sk_buff *skb, u8 *bssid,
@@ -925,17 +922,15 @@ static inline void ieee80211_start_mesh(struct net_device *dev)
 {}
 {}
 #endif
 #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);
 		     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 */
 /* tx handling */
 void ieee80211_clear_tx_pending(struct ieee80211_local *local);
 void ieee80211_clear_tx_pending(struct ieee80211_local *local);

+ 169 - 223
net/mac80211/iface.c

@@ -2,6 +2,7 @@
  * Copyright 2002-2005, Instant802 Networks, Inc.
  * Copyright 2002-2005, Instant802 Networks, Inc.
  * Copyright 2005-2006, Devicescape Software, Inc.
  * Copyright 2005-2006, Devicescape Software, Inc.
  * Copyright (c) 2006 Jiri Benc <jbenc@suse.cz>
  * 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
  * 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
  * it under the terms of the GNU General Public License version 2 as
@@ -17,145 +18,91 @@
 #include "debugfs_netdev.h"
 #include "debugfs_netdev.h"
 #include "mesh.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;
 	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++)
 	for (i = 0; i < IEEE80211_FRAGMENT_MAX; i++)
 		__skb_queue_purge(&sdata->fragments[i].skb_list);
 		__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->vif.type = type;
 
 
-	sdata->basic_rates = 0;
+	/* only monitor differs */
+	sdata->dev->type = ARPHRD_ETHER;
 
 
 	switch (type) {
 	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:
 	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);
 		skb_queue_head_init(&sdata->u.ap.ps_bc_buf);
-		sdata->bss = &sdata->u.ap;
 		INIT_LIST_HEAD(&sdata->u.ap.vlans);
 		INIT_LIST_HEAD(&sdata->u.ap.vlans);
 		break;
 		break;
 	case IEEE80211_IF_TYPE_MESH_POINT:
 	case IEEE80211_IF_TYPE_MESH_POINT:
 	case IEEE80211_IF_TYPE_STA:
 	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;
 		ifsta = &sdata->u.sta;
 		INIT_WORK(&ifsta->work, ieee80211_sta_work);
 		INIT_WORK(&ifsta->work, ieee80211_sta_work);
 		setup_timer(&ifsta->timer, ieee80211_sta_timer,
 		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)
 		if (ieee80211_num_regular_queues(&sdata->local->hw) >= 4)
 			ifsta->flags |= IEEE80211_STA_WMM_ENABLED;
 			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))
 		if (ieee80211_vif_is_mesh(&sdata->vif))
 			ieee80211_mesh_init_sdata(sdata);
 			ieee80211_mesh_init_sdata(sdata);
 		break;
 		break;
-	}
 	case IEEE80211_IF_TYPE_MNTR:
 	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 |
 		sdata->u.mntr_flags = MONITOR_FLAG_CONTROL |
 				      MONITOR_FLAG_OTHER_BSS;
 				      MONITOR_FLAG_OTHER_BSS;
 		break;
 		break;
+	case IEEE80211_IF_TYPE_WDS:
+	case IEEE80211_IF_TYPE_VLAN:
+		break;
 	case IEEE80211_IF_TYPE_INVALID:
 	case IEEE80211_IF_TYPE_INVALID:
 		BUG();
 		BUG();
 		break;
 		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();
 	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();
 	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);
+	}
 }
 }

+ 55 - 116
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 */
 	/* we hold the RTNL here so can safely walk the list */
 	list_for_each_entry(sdata, &local->interfaces, list) {
 	list_for_each_entry(sdata, &local->interfaces, list) {
-		if (sdata->dev != dev && netif_running(sdata->dev)) {
+		if (netif_running(sdata->dev)) {
 			res = 0;
 			res = 0;
 			break;
 			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 */
 	/* we hold the RTNL here so can safely walk the list */
 	list_for_each_entry(sdata, &local->interfaces, 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);
 			dev_close(sdata->dev);
 
 
 	return 0;
 	return 0;
@@ -194,7 +194,7 @@ static int ieee80211_open(struct net_device *dev)
 	list_for_each_entry(nsdata, &local->interfaces, list) {
 	list_for_each_entry(nsdata, &local->interfaces, list) {
 		struct net_device *ndev = nsdata->dev;
 		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
 			 * Allow only a single IBSS interface to be up at any
 			 * time. This is restricted because beacon distribution
 			 * time. This is restricted because beacon distribution
@@ -209,30 +209,6 @@ static int ieee80211_open(struct net_device *dev)
 			    nsdata->vif.type == IEEE80211_IF_TYPE_IBSS)
 			    nsdata->vif.type == IEEE80211_IF_TYPE_IBSS)
 				return -EBUSY;
 				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
 			 * The remaining checks are only performed for interfaces
 			 * with the same MAC address.
 			 * 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 &&
 			if (sdata->vif.type == IEEE80211_IF_TYPE_VLAN &&
 			    nsdata->vif.type == IEEE80211_IF_TYPE_AP)
 			    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;
 			return -ENOLINK;
 		break;
 		break;
 	case IEEE80211_IF_TYPE_VLAN:
 	case IEEE80211_IF_TYPE_VLAN:
-		if (!sdata->u.vlan.ap)
+		if (!sdata->bss)
 			return -ENOLINK;
 			return -ENOLINK;
+		list_add(&sdata->u.vlan.list, &sdata->bss->vlans);
 		break;
 		break;
 	case IEEE80211_IF_TYPE_AP:
 	case IEEE80211_IF_TYPE_AP:
+		sdata->bss = &sdata->u.ap;
+		break;
 	case IEEE80211_IF_TYPE_STA:
 	case IEEE80211_IF_TYPE_STA:
 	case IEEE80211_IF_TYPE_MNTR:
 	case IEEE80211_IF_TYPE_MNTR:
 	case IEEE80211_IF_TYPE_IBSS:
 	case IEEE80211_IF_TYPE_IBSS:
@@ -283,14 +262,13 @@ static int ieee80211_open(struct net_device *dev)
 		if (local->ops->start)
 		if (local->ops->start)
 			res = local->ops->start(local_to_hw(local));
 			res = local->ops->start(local_to_hw(local));
 		if (res)
 		if (res)
-			return res;
+			goto err_del_bss;
 		need_hw_reconfig = 1;
 		need_hw_reconfig = 1;
 		ieee80211_led_radio(local, local->hw.conf.radio_enabled);
 		ieee80211_led_radio(local, local->hw.conf.radio_enabled);
 	}
 	}
 
 
 	switch (sdata->vif.type) {
 	switch (sdata->vif.type) {
 	case IEEE80211_IF_TYPE_VLAN:
 	case IEEE80211_IF_TYPE_VLAN:
-		list_add(&sdata->u.vlan.list, &sdata->u.vlan.ap->u.ap.vlans);
 		/* no need to tell driver */
 		/* no need to tell driver */
 		break;
 		break;
 	case IEEE80211_IF_TYPE_MNTR:
 	case IEEE80211_IF_TYPE_MNTR:
@@ -329,7 +307,8 @@ static int ieee80211_open(struct net_device *dev)
 		if (res)
 		if (res)
 			goto err_stop;
 			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);
 		changed |= ieee80211_reset_erp_info(dev);
 		ieee80211_bss_info_change_notify(sdata, changed);
 		ieee80211_bss_info_change_notify(sdata, changed);
 		ieee80211_enable_keys(sdata);
 		ieee80211_enable_keys(sdata);
@@ -404,6 +383,10 @@ static int ieee80211_open(struct net_device *dev)
  err_stop:
  err_stop:
 	if (!local->open_count && local->ops->stop)
 	if (!local->open_count && local->ops->stop)
 		local->ops->stop(local_to_hw(local));
 		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;
 	return res;
 }
 }
 
 
@@ -486,7 +469,6 @@ static int ieee80211_stop(struct net_device *dev)
 	switch (sdata->vif.type) {
 	switch (sdata->vif.type) {
 	case IEEE80211_IF_TYPE_VLAN:
 	case IEEE80211_IF_TYPE_VLAN:
 		list_del(&sdata->u.vlan.list);
 		list_del(&sdata->u.vlan.list);
-		sdata->u.vlan.ap = NULL;
 		/* no need to tell driver */
 		/* no need to tell driver */
 		break;
 		break;
 	case IEEE80211_IF_TYPE_MNTR:
 	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);
 		local->ops->remove_interface(local_to_hw(local), &conf);
 	}
 	}
 
 
+	sdata->bss = NULL;
+
 	if (local->open_count == 0) {
 	if (local->open_count == 0) {
 		if (netif_running(local->mdev))
 		if (netif_running(local->mdev))
 			dev_close(local->mdev);
 			dev_close(local->mdev);
@@ -988,7 +972,6 @@ static const struct header_ops ieee80211_header_ops = {
 	.cache_update	= eth_header_cache_update,
 	.cache_update	= eth_header_cache_update,
 };
 };
 
 
-/* Must not be called for mdev */
 void ieee80211_if_setup(struct net_device *dev)
 void ieee80211_if_setup(struct net_device *dev)
 {
 {
 	ether_setup(dev);
 	ether_setup(dev);
@@ -998,62 +981,52 @@ void ieee80211_if_setup(struct net_device *dev)
 	dev->change_mtu = ieee80211_change_mtu;
 	dev->change_mtu = ieee80211_change_mtu;
 	dev->open = ieee80211_open;
 	dev->open = ieee80211_open;
 	dev->stop = ieee80211_stop;
 	dev->stop = ieee80211_stop;
-	dev->destructor = ieee80211_if_free;
+	dev->destructor = free_netdev;
 }
 }
 
 
 /* everything else */
 /* 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;
 	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;
 		return 0;
 
 
 	memset(&conf, 0, sizeof(conf));
 	memset(&conf, 0, sizeof(conf));
-	conf.type = sdata->vif.type;
+	conf.changed = changed;
+
 	if (sdata->vif.type == IEEE80211_IF_TYPE_STA ||
 	if (sdata->vif.type == IEEE80211_IF_TYPE_STA ||
 	    sdata->vif.type == IEEE80211_IF_TYPE_IBSS) {
 	    sdata->vif.type == IEEE80211_IF_TYPE_IBSS) {
 		conf.bssid = sdata->u.sta.bssid;
 		conf.bssid = sdata->u.sta.bssid;
 		conf.ssid = sdata->u.sta.ssid;
 		conf.ssid = sdata->u.sta.ssid;
 		conf.ssid_len = sdata->u.sta.ssid_len;
 		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) {
 	} else if (sdata->vif.type == IEEE80211_IF_TYPE_AP) {
+		conf.bssid = sdata->dev->dev_addr;
 		conf.ssid = sdata->u.ap.ssid;
 		conf.ssid = sdata->u.ap.ssid;
 		conf.ssid_len = sdata->u.ap.ssid_len;
 		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)
 int ieee80211_hw_config(struct ieee80211_local *local)
@@ -1659,7 +1632,7 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
 	int result;
 	int result;
 	enum ieee80211_band band;
 	enum ieee80211_band band;
 	struct net_device *mdev;
 	struct net_device *mdev;
-	struct ieee80211_sub_if_data *sdata;
+	struct wireless_dev *mwdev;
 
 
 	/*
 	/*
 	 * generic code guarantees at least one band,
 	 * generic code guarantees at least one band,
@@ -1699,8 +1672,7 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
 	hw->ampdu_queues = 0;
 	hw->ampdu_queues = 0;
 #endif
 #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,
 			       "wmaster%d", ether_setup,
 			       ieee80211_num_queues(hw));
 			       ieee80211_num_queues(hw));
 	if (!mdev)
 	if (!mdev)
@@ -1709,13 +1681,13 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
 	if (ieee80211_num_queues(hw) > 1)
 	if (ieee80211_num_queues(hw) > 1)
 		mdev->features |= NETIF_F_MULTI_QUEUE;
 		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;
 	local->mdev = mdev;
 
 
-	ieee80211_rx_bss_list_init(mdev);
+	ieee80211_rx_bss_list_init(local);
 
 
 	mdev->hard_start_xmit = ieee80211_master_start_xmit;
 	mdev->hard_start_xmit = ieee80211_master_start_xmit;
 	mdev->open = ieee80211_master_open;
 	mdev->open = ieee80211_master_open;
@@ -1724,16 +1696,6 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
 	mdev->header_ops = &ieee80211_header_ops;
 	mdev->header_ops = &ieee80211_header_ops;
 	mdev->set_multicast_list = ieee80211_master_set_multicast_list;
 	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;
 	name = wiphy_dev(local->hw.wiphy)->driver->name;
 	local->hw.workqueue = create_freezeable_workqueue(name);
 	local->hw.workqueue = create_freezeable_workqueue(name);
 	if (!local->hw.workqueue) {
 	if (!local->hw.workqueue) {
@@ -1779,9 +1741,6 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
 	if (result < 0)
 	if (result < 0)
 		goto fail_dev;
 		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,
 	result = ieee80211_init_rate_ctrl_alg(local,
 					      hw->rate_control_algorithm);
 					      hw->rate_control_algorithm);
 	if (result < 0) {
 	if (result < 0) {
@@ -1801,13 +1760,12 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
 	ieee80211_install_qdisc(local->mdev);
 	ieee80211_install_qdisc(local->mdev);
 
 
 	/* add one default STA interface */
 	/* 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);
 				  IEEE80211_IF_TYPE_STA, NULL);
 	if (result)
 	if (result)
 		printk(KERN_WARNING "%s: Failed to add default virtual iface\n",
 		printk(KERN_WARNING "%s: Failed to add default virtual iface\n",
 		       wiphy_name(local->hw.wiphy));
 		       wiphy_name(local->hw.wiphy));
 
 
-	local->reg_state = IEEE80211_DEV_REGISTERED;
 	rtnl_unlock();
 	rtnl_unlock();
 
 
 	ieee80211_led_init(local);
 	ieee80211_led_init(local);
@@ -1817,7 +1775,6 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
 fail_wep:
 fail_wep:
 	rate_control_deinitialize(local);
 	rate_control_deinitialize(local);
 fail_rate:
 fail_rate:
-	ieee80211_debugfs_remove_netdev(IEEE80211_DEV_TO_SUB_IF(local->mdev));
 	unregister_netdevice(local->mdev);
 	unregister_netdevice(local->mdev);
 	local->mdev = NULL;
 	local->mdev = NULL;
 fail_dev:
 fail_dev:
@@ -1827,10 +1784,8 @@ fail_sta_info:
 	debugfs_hw_del(local);
 	debugfs_hw_del(local);
 	destroy_workqueue(local->hw.workqueue);
 	destroy_workqueue(local->hw.workqueue);
 fail_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:
 fail_mdev_alloc:
 	wiphy_unregister(local->hw.wiphy);
 	wiphy_unregister(local->hw.wiphy);
 	return result;
 	return result;
@@ -1840,42 +1795,27 @@ EXPORT_SYMBOL(ieee80211_register_hw);
 void ieee80211_unregister_hw(struct ieee80211_hw *hw)
 void ieee80211_unregister_hw(struct ieee80211_hw *hw)
 {
 {
 	struct ieee80211_local *local = hw_to_local(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->tx_pending_tasklet);
 	tasklet_kill(&local->tasklet);
 	tasklet_kill(&local->tasklet);
 
 
 	rtnl_lock();
 	rtnl_lock();
 
 
-	BUG_ON(local->reg_state != IEEE80211_DEV_REGISTERED);
-
-	local->reg_state = IEEE80211_DEV_UNREGISTERED;
-
 	/*
 	/*
 	 * At this point, interface list manipulations are fine
 	 * At this point, interface list manipulations are fine
 	 * because the driver cannot be handing us frames any
 	 * because the driver cannot be handing us frames any
 	 * more and the tasklet is killed.
 	 * 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 */
 	/* then, finally, remove the master interface */
-	__ieee80211_if_del(local, IEEE80211_DEV_TO_SUB_IF(local->mdev));
+	unregister_netdevice(local->mdev);
 
 
 	rtnl_unlock();
 	rtnl_unlock();
 
 
-	ieee80211_rx_bss_list_deinit(local->mdev);
+	ieee80211_rx_bss_list_deinit(local);
 	ieee80211_clear_tx_pending(local);
 	ieee80211_clear_tx_pending(local);
 	sta_info_stop(local);
 	sta_info_stop(local);
 	rate_control_deinitialize(local);
 	rate_control_deinitialize(local);
@@ -1892,8 +1832,7 @@ void ieee80211_unregister_hw(struct ieee80211_hw *hw)
 	wiphy_unregister(local->hw.wiphy);
 	wiphy_unregister(local->hw.wiphy);
 	ieee80211_wep_free(local);
 	ieee80211_wep_free(local);
 	ieee80211_led_exit(local);
 	ieee80211_led_exit(local);
-	ieee80211_if_free(local->mdev);
-	local->mdev = NULL;
+	free_netdev(local->mdev);
 }
 }
 EXPORT_SYMBOL(ieee80211_unregister_hw);
 EXPORT_SYMBOL(ieee80211_unregister_hw);
 
 

+ 66 - 106
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 *
 static struct ieee80211_sta_bss *
 ieee80211_rx_bss_get(struct net_device *dev, u8 *bssid, int freq,
 ieee80211_rx_bss_get(struct net_device *dev, u8 *bssid, int freq,
 		     u8 *ssid, u8 ssid_len);
 		     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);
 				 struct ieee80211_sta_bss *bss);
 static int ieee80211_sta_find_ibss(struct net_device *dev,
 static int ieee80211_sta_find_ibss(struct net_device *dev,
 				   struct ieee80211_if_sta *ifsta);
 				   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.aifs = pos[0] & 0x0f;
 		params.cw_max = ecw2cw((pos[1] & 0xf0) >> 4);
 		params.cw_max = ecw2cw((pos[1] & 0xf0) >> 4);
 		params.cw_min = ecw2cw(pos[1] & 0x0f);
 		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
 #ifdef CONFIG_MAC80211_VERBOSE_DEBUG
 		printk(KERN_DEBUG "%s: WMM queue=%d aci=%d acm=%d aifs=%d "
 		printk(KERN_DEBUG "%s: WMM queue=%d aci=%d acm=%d aifs=%d "
 		       "cWmin=%d cWmax=%d txop=%d\n",
 		       "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);
 			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) {
 		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))
 		    (local->hw.flags & IEEE80211_HW_SPECTRUM_MGMT))
 			capab |= WLAN_CAPABILITY_SPECTRUM_MGMT;
 			capab |= WLAN_CAPABILITY_SPECTRUM_MGMT;
 
 
-		ieee80211_rx_bss_put(dev, bss);
+		ieee80211_rx_bss_put(local, bss);
 	} else {
 	} else {
 		rates = ~0;
 		rates = ~0;
 		rates_len = sband->n_bitrates;
 		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);
 	wep_privacy = !!ieee80211_sta_wep_configured(dev);
 	privacy_invoked = !!(ifsta->flags & IEEE80211_STA_PRIVACY_INVOKED);
 	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))
 	if ((bss_privacy == wep_privacy) || (bss_privacy == privacy_invoked))
 		return 0;
 		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_signal = bss->signal;
 			sta->last_qual = bss->qual;
 			sta->last_qual = bss->qual;
 			sta->last_noise = bss->noise;
 			sta->last_noise = bss->noise;
-			ieee80211_rx_bss_put(dev, bss);
+			ieee80211_rx_bss_put(local, bss);
 		}
 		}
 
 
 		err = sta_info_insert(sta);
 		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 */
 /* 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_sta_bss *bss)
 {
 {
-	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
 	struct ieee80211_sta_bss *b, *prev = NULL;
 	struct ieee80211_sta_bss *b, *prev = NULL;
 	b = local->sta_bss_hash[STA_HASH(bss->bssid)];
 	b = local->sta_bss_hash[STA_HASH(bss->bssid)];
 	while (b) {
 	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_sta_bss *bss)
 {
 {
-	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
-
 	local_bh_disable();
 	local_bh_disable();
 	if (!atomic_dec_and_lock(&bss->users, &local->sta_bss_lock)) {
 	if (!atomic_dec_and_lock(&bss->users, &local->sta_bss_lock)) {
 		local_bh_enable();
 		local_bh_enable();
 		return;
 		return;
 	}
 	}
 
 
-	__ieee80211_rx_bss_hash_del(dev, bss);
+	__ieee80211_rx_bss_hash_del(local, bss);
 	list_del(&bss->list);
 	list_del(&bss->list);
 	spin_unlock_bh(&local->sta_bss_lock);
 	spin_unlock_bh(&local->sta_bss_lock);
 	ieee80211_rx_bss_free(bss);
 	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);
 	spin_lock_init(&local->sta_bss_lock);
 	INIT_LIST_HEAD(&local->sta_bss_list);
 	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;
 	struct ieee80211_sta_bss *bss, *tmp;
 
 
 	list_for_each_entry_safe(bss, tmp, &local->sta_bss_list, list)
 	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;
 	int res, rates, i, j;
 	struct sk_buff *skb;
 	struct sk_buff *skb;
 	struct ieee80211_mgmt *mgmt;
 	struct ieee80211_mgmt *mgmt;
-	struct ieee80211_tx_info *control;
-	struct rate_selection ratesel;
 	u8 *pos;
 	u8 *pos;
 	struct ieee80211_sub_if_data *sdata;
 	struct ieee80211_sub_if_data *sdata;
 	struct ieee80211_supported_band *sband;
 	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));
 		local->ops->reset_tsf(local_to_hw(local));
 	}
 	}
 	memcpy(ifsta->bssid, bss->bssid, ETH_ALEN);
 	memcpy(ifsta->bssid, bss->bssid, ETH_ALEN);
-	res = ieee80211_if_config(dev);
+	res = ieee80211_if_config(sdata, IEEE80211_IFCC_BSSID);
 	if (res)
 	if (res)
 		return res;
 		return res;
 
 
@@ -2444,19 +2437,16 @@ static int ieee80211_sta_join_ibss(struct net_device *dev,
 	if (res)
 	if (res)
 		return res;
 		return res;
 
 
-	/* Set beacon template */
+	/* Build IBSS probe response */
 	skb = dev_alloc_skb(local->hw.extra_tx_headroom + 400);
 	skb = dev_alloc_skb(local->hw.extra_tx_headroom + 400);
-	do {
-		if (!skb)
-			break;
-
+	if (skb) {
 		skb_reserve(skb, local->hw.extra_tx_headroom);
 		skb_reserve(skb, local->hw.extra_tx_headroom);
 
 
 		mgmt = (struct ieee80211_mgmt *)
 		mgmt = (struct ieee80211_mgmt *)
 			skb_put(skb, 24 + sizeof(mgmt->u.beacon));
 			skb_put(skb, 24 + sizeof(mgmt->u.beacon));
 		memset(mgmt, 0, 24 + sizeof(mgmt->u.beacon));
 		memset(mgmt, 0, 24 + sizeof(mgmt->u.beacon));
 		mgmt->frame_control = IEEE80211_FC(IEEE80211_FTYPE_MGMT,
 		mgmt->frame_control = IEEE80211_FC(IEEE80211_FTYPE_MGMT,
-						   IEEE80211_STYPE_BEACON);
+						   IEEE80211_STYPE_PROBE_RESP);
 		memset(mgmt->da, 0xff, ETH_ALEN);
 		memset(mgmt->da, 0xff, ETH_ALEN);
 		memcpy(mgmt->sa, dev->dev_addr, ETH_ALEN);
 		memcpy(mgmt->sa, dev->dev_addr, ETH_ALEN);
 		memcpy(mgmt->bssid, ifsta->bssid, 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);
 			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;
 	ifsta->state = IEEE80211_IBSS_JOINED;
 	mod_timer(&ifsta->timer, jiffies + IEEE80211_IBSS_MERGE_INTERVAL);
 	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 &&
 	if (sdata->vif.type != IEEE80211_IF_TYPE_IBSS &&
 	    bss->probe_resp && beacon) {
 	    bss->probe_resp && beacon) {
-		ieee80211_rx_bss_put(dev, bss);
+		ieee80211_rx_bss_put(local, bss);
 		return;
 		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);
 	free_plinks = mesh_plink_availables(sdata);
 	if (free_plinks != sdata->u.sta.accepting_plinks)
 	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 +
 	mod_timer(&ifsta->timer, jiffies +
 			IEEE80211_MESH_HOUSEKEEPING_INTERVAL);
 			IEEE80211_MESH_HOUSEKEEPING_INTERVAL);
@@ -3578,7 +3529,7 @@ static int ieee80211_sta_config_auth(struct net_device *dev,
 					       selected->ssid_len);
 					       selected->ssid_len);
 		ieee80211_sta_set_bssid(dev, selected->bssid);
 		ieee80211_sta_set_bssid(dev, selected->bssid);
 		ieee80211_sta_def_wmm_params(dev, selected, 0);
 		ieee80211_sta_def_wmm_params(dev, selected, 0);
-		ieee80211_rx_bss_put(dev, selected);
+		ieee80211_rx_bss_put(local, selected);
 		ifsta->state = IEEE80211_AUTHENTICATE;
 		ifsta->state = IEEE80211_AUTHENTICATE;
 		ieee80211_sta_reset_auth(dev, ifsta);
 		ieee80211_sta_reset_auth(dev, ifsta);
 		return 0;
 		return 0;
@@ -3655,7 +3606,7 @@ static int ieee80211_sta_create_ibss(struct net_device *dev,
 	}
 	}
 
 
 	ret = ieee80211_sta_join_ibss(dev, ifsta, bss);
 	ret = ieee80211_sta_join_ibss(dev, ifsta, bss);
-	ieee80211_rx_bss_put(dev, bss);
+	ieee80211_rx_bss_put(local, bss);
 	return ret;
 	return ret;
 }
 }
 
 
@@ -3711,7 +3662,7 @@ static int ieee80211_sta_find_ibss(struct net_device *dev,
 		       " based on configured SSID\n",
 		       " based on configured SSID\n",
 		       dev->name, print_mac(mac, bssid));
 		       dev->name, print_mac(mac, bssid));
 		ret = ieee80211_sta_join_ibss(dev, ifsta, bss);
 		ret = ieee80211_sta_join_ibss(dev, ifsta, bss);
-		ieee80211_rx_bss_put(dev, bss);
+		ieee80211_rx_bss_put(local, bss);
 		return ret;
 		return ret;
 	}
 	}
 #ifdef CONFIG_MAC80211_IBSS_DEBUG
 #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_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
 	struct ieee80211_if_sta *ifsta;
 	struct ieee80211_if_sta *ifsta;
+	int res;
 
 
 	if (len > IEEE80211_MAX_SSID_LEN)
 	if (len > IEEE80211_MAX_SSID_LEN)
 		return -EINVAL;
 		return -EINVAL;
 
 
 	ifsta = &sdata->u.sta;
 	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;
 		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)
 	if (len)
 		ifsta->flags |= IEEE80211_STA_SSID_SET;
 		ifsta->flags |= IEEE80211_STA_SSID_SET;
 	else
 	else
 		ifsta->flags &= ~IEEE80211_STA_SSID_SET;
 		ifsta->flags &= ~IEEE80211_STA_SSID_SET;
+
 	if (sdata->vif.type == IEEE80211_IF_TYPE_IBSS &&
 	if (sdata->vif.type == IEEE80211_IF_TYPE_IBSS &&
 	    !(ifsta->flags & IEEE80211_STA_BSSID_SET)) {
 	    !(ifsta->flags & IEEE80211_STA_BSSID_SET)) {
 		ifsta->ibss_join_req = jiffies;
 		ifsta->ibss_join_req = jiffies;
 		ifsta->state = IEEE80211_IBSS_SEARCH;
 		ifsta->state = IEEE80211_IBSS_SEARCH;
 		return ieee80211_sta_find_ibss(dev, ifsta);
 		return ieee80211_sta_find_ibss(dev, ifsta);
 	}
 	}
+
 	return 0;
 	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) {
 	if (memcmp(ifsta->bssid, bssid, ETH_ALEN) != 0) {
 		memcpy(ifsta->bssid, bssid, ETH_ALEN);
 		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) {
 		if (res) {
 			printk(KERN_DEBUG "%s: Failed to config new BSSID to "
 			printk(KERN_DEBUG "%s: Failed to config new BSSID to "
 			       "the low-level driver\n", dev->name);
 			       "the low-level driver\n", dev->name);
@@ -3907,11 +3880,6 @@ void ieee80211_scan_completed(struct ieee80211_hw *hw)
 
 
 	rcu_read_lock();
 	rcu_read_lock();
 	list_for_each_entry_rcu(sdata, &local->interfaces, list) {
 	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 */
 		/* Tell AP we're back */
 		if (sdata->vif.type == IEEE80211_IF_TYPE_STA &&
 		if (sdata->vif.type == IEEE80211_IF_TYPE_STA &&
 		    sdata->u.sta.flags & IEEE80211_STA_ASSOCIATED)
 		    sdata->u.sta.flags & IEEE80211_STA_ASSOCIATED)
@@ -4077,12 +4045,6 @@ static int ieee80211_sta_start_scan(struct net_device *dev,
 
 
 	rcu_read_lock();
 	rcu_read_lock();
 	list_for_each_entry_rcu(sdata, &local->interfaces, list) {
 	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);
 		netif_stop_queue(sdata->dev);
 		if (sdata->vif.type == IEEE80211_IF_TYPE_STA &&
 		if (sdata->vif.type == IEEE80211_IF_TYPE_STA &&
 		    (sdata->u.sta.flags & IEEE80211_STA_ASSOCIATED))
 		    (sdata->u.sta.flags & IEEE80211_STA_ASSOCIATED))
@@ -4398,7 +4360,7 @@ struct sta_info *ieee80211_ibss_add_sta(struct net_device *dev,
 		return NULL;
 		return NULL;
 	}
 	}
 
 
-	if (!ieee80211_bssid_match(bssid, sdata->u.sta.bssid))
+	if (compare_ether_addr(bssid, sdata->u.sta.bssid))
 		return NULL;
 		return NULL;
 
 
 #ifdef CONFIG_MAC80211_VERBOSE_DEBUG
 #ifdef CONFIG_MAC80211_VERBOSE_DEBUG
@@ -4473,12 +4435,10 @@ void ieee80211_notify_mac(struct ieee80211_hw *hw,
 	case IEEE80211_NOTIFY_RE_ASSOC:
 	case IEEE80211_NOTIFY_RE_ASSOC:
 		rcu_read_lock();
 		rcu_read_lock();
 		list_for_each_entry_rcu(sdata, &local->interfaces, list) {
 		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();
 		rcu_read_unlock();
 		break;
 		break;

+ 4 - 4
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. */
 	/* Don't update the state if we're not controlling the rate. */
 	sdata = sta->sdata;
 	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;
 		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. */
 	/* If a forced rate is in effect, select it. */
 	sdata = IEEE80211_DEV_TO_SUB_IF(dev);
 	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;
 	rateidx = sta->txrate_idx;
 
 

+ 19 - 19
net/mac80211/rx.c

@@ -334,13 +334,18 @@ static void ieee80211_parse_qos(struct ieee80211_rx_data *rx)
 		else
 		else
 			rx->flags &= ~IEEE80211_RX_AMSDU;
 			rx->flags &= ~IEEE80211_RX_AMSDU;
 	} else {
 	} 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;
 	rx->queue = tid;
@@ -647,8 +652,7 @@ static void ap_sta_ps_start(struct net_device *dev, struct sta_info *sta)
 
 
 	sdata = sta->sdata;
 	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);
 	set_and_clear_sta_flags(sta, WLAN_STA_PS, WLAN_STA_PSPOLL);
 #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
 #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
 	printk(KERN_DEBUG "%s: STA %s aid %d enters power save mode\n",
 	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;
 	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);
 	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_qual = rx->status->qual;
 	sta->last_noise = rx->status->noise;
 	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
 		/* Change STA power saving mode only in the end of a frame
 		 * exchange sequence */
 		 * exchange sequence */
 		if (test_sta_flags(sta, WLAN_STA_PS) &&
 		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;
 				return 0;
 			rx->flags &= ~IEEE80211_RX_RA_MATCH;
 			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;
 		break;
 	case IEEE80211_IF_TYPE_WDS:
 	case IEEE80211_IF_TYPE_WDS:
 		if (bssid || !ieee80211_is_data(hdr->frame_control))
 		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];
 	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;
 		goto end_reorder;
 
 
 	/* new un-ordered ampdu frame - process it */
 	/* new un-ordered ampdu frame - process it */

+ 21 - 8
net/mac80211/sta_info.c

@@ -320,7 +320,9 @@ int sta_info_insert(struct sta_info *sta)
 	/* notify driver */
 	/* notify driver */
 	if (local->ops->sta_notify) {
 	if (local->ops->sta_notify) {
 		if (sdata->vif.type == IEEE80211_IF_TYPE_VLAN)
 		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,
 		local->ops->sta_notify(local_to_hw(local), &sdata->vif,
 				       STA_NOTIFY_ADD, sta->addr);
 				       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,
 static void __sta_info_set_tim_bit(struct ieee80211_if_ap *bss,
 				   struct sta_info *sta)
 				   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) {
 	if (sta->local->ops->set_tim) {
 		sta->local->tim_in_locked_section = true;
 		sta->local->tim_in_locked_section = true;
 		sta->local->ops->set_tim(local_to_hw(sta->local), sta->aid, 1);
 		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;
 	unsigned long flags;
 
 
+	BUG_ON(!sta->sdata->bss);
+
 	spin_lock_irqsave(&sta->local->sta_lock, flags);
 	spin_lock_irqsave(&sta->local->sta_lock, flags);
 	__sta_info_set_tim_bit(sta->sdata->bss, sta);
 	__sta_info_set_tim_bit(sta->sdata->bss, sta);
 	spin_unlock_irqrestore(&sta->local->sta_lock, flags);
 	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,
 static void __sta_info_clear_tim_bit(struct ieee80211_if_ap *bss,
 				     struct sta_info *sta)
 				     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) {
 	if (sta->local->ops->set_tim) {
 		sta->local->tim_in_locked_section = true;
 		sta->local->tim_in_locked_section = true;
 		sta->local->ops->set_tim(local_to_hw(sta->local), sta->aid, 0);
 		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;
 	unsigned long flags;
 
 
+	BUG_ON(!sta->sdata->bss);
+
 	spin_lock_irqsave(&sta->local->sta_lock, flags);
 	spin_lock_irqsave(&sta->local->sta_lock, flags);
 	__sta_info_clear_tim_bit(sta->sdata->bss, sta);
 	__sta_info_clear_tim_bit(sta->sdata->bss, sta);
 	spin_unlock_irqrestore(&sta->local->sta_lock, flags);
 	spin_unlock_irqrestore(&sta->local->sta_lock, flags);
@@ -437,8 +447,9 @@ void __sta_info_unlink(struct sta_info **sta)
 	list_del(&(*sta)->list);
 	list_del(&(*sta)->list);
 
 
 	if (test_and_clear_sta_flags(*sta, WLAN_STA_PS)) {
 	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);
 		__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 (local->ops->sta_notify) {
 		if (sdata->vif.type == IEEE80211_IF_TYPE_VLAN)
 		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,
 		local->ops->sta_notify(local_to_hw(local), &sdata->vif,
 				       STA_NOTIFY_REMOVE, (*sta)->addr);
 				       STA_NOTIFY_REMOVE, (*sta)->addr);

+ 1 - 0
net/mac80211/sta_info.h

@@ -285,6 +285,7 @@ struct sta_info {
 	unsigned long tx_fragments;
 	unsigned long tx_fragments;
 	int txrate_idx;
 	int txrate_idx;
 	int last_txrate_idx;
 	int last_txrate_idx;
+	u16 tid_seq[IEEE80211_QOS_CTL_TID_MASK + 1];
 #ifdef CONFIG_MAC80211_DEBUG_COUNTERS
 #ifdef CONFIG_MAC80211_DEBUG_COUNTERS
 	unsigned int wme_tx_queue[NUM_RX_DATA_QUEUES];
 	unsigned int wme_tx_queue[NUM_RX_DATA_QUEUES];
 #endif
 #endif

+ 79 - 47
net/mac80211/tx.c

@@ -38,16 +38,6 @@
 
 
 /* misc utils */
 /* 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
 #ifdef CONFIG_MAC80211_LOWTX_FRAME_DUMP
 static void ieee80211_dump_frame(const char *ifname, const char *title,
 static void ieee80211_dump_frame(const char *ifname, const char *title,
 				 const struct sk_buff *skb)
 				 const struct sk_buff *skb)
@@ -274,17 +264,6 @@ ieee80211_tx_h_check_assoc(struct ieee80211_tx_data *tx)
 	return TX_CONTINUE;
 	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
 /* 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
  * of buffered frames for power saving STAs. This situation should not really
  * happen often during normal operation, so dropping the oldest buffered packet
  * 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) {
 	list_for_each_entry_rcu(sdata, &local->interfaces, list) {
 		struct ieee80211_if_ap *ap;
 		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;
 			continue;
 		ap = &sdata->u.ap;
 		ap = &sdata->u.ap;
 		skb = skb_dequeue(&ap->ps_bc_buf);
 		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.
 	 * 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;
 		return TX_CONTINUE;
 
 
 	/* no stations in PS mode */
 	/* no stations in PS mode */
@@ -638,6 +620,49 @@ ieee80211_tx_h_misc(struct ieee80211_tx_data *tx)
 	return TX_CONTINUE;
 	return TX_CONTINUE;
 }
 }
 
 
+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
 static ieee80211_tx_result debug_noinline
 ieee80211_tx_h_fragment(struct ieee80211_tx_data *tx)
 ieee80211_tx_h_fragment(struct ieee80211_tx_data *tx)
 {
 {
@@ -1107,12 +1132,12 @@ static int invoke_tx_handlers(struct ieee80211_tx_data *tx)
 		goto txh_done;
 		goto txh_done;
 
 
 	CALL_TXH(ieee80211_tx_h_check_assoc)
 	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_ps_buf)
 	CALL_TXH(ieee80211_tx_h_select_key)
 	CALL_TXH(ieee80211_tx_h_select_key)
 	CALL_TXH(ieee80211_tx_h_michael_mic_add)
 	CALL_TXH(ieee80211_tx_h_michael_mic_add)
 	CALL_TXH(ieee80211_tx_h_rate_ctrl)
 	CALL_TXH(ieee80211_tx_h_rate_ctrl)
 	CALL_TXH(ieee80211_tx_h_misc)
 	CALL_TXH(ieee80211_tx_h_misc)
+	CALL_TXH(ieee80211_tx_h_sequence)
 	CALL_TXH(ieee80211_tx_h_fragment)
 	CALL_TXH(ieee80211_tx_h_fragment)
 	/* handlers after fragment must be aware of tx info fragmentation! */
 	/* handlers after fragment must be aware of tx info fragmentation! */
 	CALL_TXH(ieee80211_tx_h_encrypt)
 	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_vif *vif)
 {
 {
 	struct ieee80211_local *local = hw_to_local(hw);
 	struct ieee80211_local *local = hw_to_local(hw);
-	struct sk_buff *skb;
+	struct sk_buff *skb = NULL;
 	struct ieee80211_tx_info *info;
 	struct ieee80211_tx_info *info;
 	struct net_device *bdev;
 	struct net_device *bdev;
 	struct ieee80211_sub_if_data *sdata = NULL;
 	struct ieee80211_sub_if_data *sdata = NULL;
 	struct ieee80211_if_ap *ap = NULL;
 	struct ieee80211_if_ap *ap = NULL;
+	struct ieee80211_if_sta *ifsta = NULL;
 	struct rate_selection rsel;
 	struct rate_selection rsel;
 	struct beacon_data *beacon;
 	struct beacon_data *beacon;
 	struct ieee80211_supported_band *sband;
 	struct ieee80211_supported_band *sband;
 	struct ieee80211_mgmt *mgmt;
 	struct ieee80211_mgmt *mgmt;
 	int *num_beacons;
 	int *num_beacons;
-	bool err = true;
 	enum ieee80211_band band = local->hw.conf.channel->band;
 	enum ieee80211_band band = local->hw.conf.channel->band;
 	u8 *pos;
 	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,
 			memcpy(skb_put(skb, beacon->head_len), beacon->head,
 			       beacon->head_len);
 			       beacon->head_len);
 
 
-			ieee80211_include_sequence(sdata,
-					(struct ieee80211_hdr *)skb->data);
-
 			/*
 			/*
 			 * Not very nice, but we want to allow the driver to call
 			 * Not very nice, but we want to allow the driver to call
 			 * ieee80211_beacon_get() as a response to the set_tim()
 			 * 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);
 				       beacon->tail, beacon->tail_len);
 
 
 			num_beacons = &ap->num_beacons;
 			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)) {
 	} else if (ieee80211_vif_is_mesh(&sdata->vif)) {
 		/* headroom, head length, tail length and maximum TIM length */
 		/* headroom, head length, tail length and maximum TIM length */
 		skb = dev_alloc_skb(local->tx_headroom + 400);
 		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);
 		mesh_mgmt_ies_add(skb, sdata->dev);
 
 
 		num_beacons = &sdata->u.sta.num_beacons;
 		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;
 		goto out;
 	}
 	}
 
 
@@ -1910,14 +1938,18 @@ struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw,
 
 
 	info->control.vif = vif;
 	info->control.vif = vif;
 	info->tx_rate_idx = rsel.rate_idx;
 	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 &&
 	if (sdata->bss_conf.use_short_preamble &&
 	    sband->bitrates[rsel.rate_idx].flags & IEEE80211_RATE_SHORT_PREAMBLE)
 	    sband->bitrates[rsel.rate_idx].flags & IEEE80211_RATE_SHORT_PREAMBLE)
 		info->flags |= IEEE80211_TX_CTL_SHORT_PREAMBLE;
 		info->flags |= IEEE80211_TX_CTL_SHORT_PREAMBLE;
+
 	info->antenna_sel_tx = local->hw.conf.antenna_sel_tx;
 	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->control.retry_limit = 1;
-	info->flags |= IEEE80211_TX_CTL_CLEAR_PS_FILT;
+
 	(*num_beacons)++;
 	(*num_beacons)++;
 out:
 out:
 	rcu_read_unlock();
 	rcu_read_unlock();

+ 0 - 4
net/mac80211/util.c

@@ -428,8 +428,6 @@ void ieee80211_iterate_active_interfaces(
 		case IEEE80211_IF_TYPE_MESH_POINT:
 		case IEEE80211_IF_TYPE_MESH_POINT:
 			break;
 			break;
 		}
 		}
-		if (sdata->dev == local->mdev)
-			continue;
 		if (netif_running(sdata->dev))
 		if (netif_running(sdata->dev))
 			iterator(data, sdata->dev->dev_addr,
 			iterator(data, sdata->dev->dev_addr,
 				 &sdata->vif);
 				 &sdata->vif);
@@ -463,8 +461,6 @@ void ieee80211_iterate_active_interfaces_atomic(
 		case IEEE80211_IF_TYPE_MESH_POINT:
 		case IEEE80211_IF_TYPE_MESH_POINT:
 			break;
 			break;
 		}
 		}
-		if (sdata->dev == local->mdev)
-			continue;
 		if (netif_running(sdata->dev))
 		if (netif_running(sdata->dev))
 			iterator(data, sdata->dev->dev_addr,
 			iterator(data, sdata->dev->dev_addr,
 				 &sdata->vif);
 				 &sdata->vif);

+ 47 - 18
net/mac80211/wext.c

@@ -296,15 +296,7 @@ static int ieee80211_ioctl_siwmode(struct net_device *dev,
 		return -EINVAL;
 		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,
 		memset(sdata->u.ap.ssid + len, 0,
 		       IEEE80211_MAX_SSID_LEN - len);
 		       IEEE80211_MAX_SSID_LEN - len);
 		sdata->u.ap.ssid_len = len;
 		sdata->u.ap.ssid_len = len;
-		return ieee80211_if_config(dev);
+		return ieee80211_if_config(sdata, IEEE80211_IFCC_SSID);
 	}
 	}
 	return -EOPNOTSUPP;
 	return -EOPNOTSUPP;
 }
 }
@@ -627,16 +619,14 @@ static int ieee80211_ioctl_siwrate(struct net_device *dev,
 	struct ieee80211_supported_band *sband;
 	struct ieee80211_supported_band *sband;
 
 
 	sdata = IEEE80211_DEV_TO_SUB_IF(dev);
 	sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-	if (!sdata->bss)
-		return -ENODEV;
 
 
 	sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
 	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 = -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 = 1 means only rate X
 	 * target_rate = X, rate->fixed = 0 means all rates <= 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)
 	if (rate->value < 0)
 		return 0;
 		return 0;
 
 
@@ -645,9 +635,9 @@ static int ieee80211_ioctl_siwrate(struct net_device *dev,
 		int this_rate = brate->bitrate;
 		int this_rate = brate->bitrate;
 
 
 		if (target_rate == this_rate) {
 		if (target_rate == this_rate) {
-			sdata->bss->max_ratectrl_rateidx = i;
+			sdata->max_ratectrl_rateidx = i;
 			if (rate->fixed)
 			if (rate->fixed)
-				sdata->bss->force_unicast_rateidx = i;
+				sdata->force_unicast_rateidx = i;
 			err = 0;
 			err = 0;
 			break;
 			break;
 		}
 		}
@@ -1009,6 +999,45 @@ static int ieee80211_ioctl_giwencode(struct net_device *dev,
 	return 0;
 	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,
 static int ieee80211_ioctl_siwauth(struct net_device *dev,
 				   struct iw_request_info *info,
 				   struct iw_request_info *info,
 				   struct iw_param *data, char *extra)
 				   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_giwretry,		/* SIOCGIWRETRY */
 	(iw_handler) ieee80211_ioctl_siwencode,		/* SIOCSIWENCODE */
 	(iw_handler) ieee80211_ioctl_siwencode,		/* SIOCSIWENCODE */
 	(iw_handler) ieee80211_ioctl_giwencode,		/* SIOCGIWENCODE */
 	(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) NULL,				/* -- hole -- */
 	(iw_handler) NULL,				/* -- hole -- */
 	(iw_handler) ieee80211_ioctl_siwgenie,		/* SIOCSIWGENIE */
 	(iw_handler) ieee80211_ioctl_siwgenie,		/* SIOCSIWGENIE */

+ 11 - 0
net/wireless/Kconfig

@@ -29,3 +29,14 @@ config WIRELESS_EXT
 
 
 	  Say N (if you can) unless you know you need wireless
 	  Say N (if you can) unless you know you need wireless
 	  extensions for external modules.
 	  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).