mac80211: add rate control rewrite and enhance the performance of the minstrel algori...
authornbd <nbd@3c298f89-4303-0410-b956-a3cf2f4a3e73>
Sat, 11 Oct 2008 01:33:09 +0000 (01:33 +0000)
committernbd <nbd@3c298f89-4303-0410-b956-a3cf2f4a3e73>
Sat, 11 Oct 2008 01:33:09 +0000 (01:33 +0000)
git-svn-id: svn://svn.openwrt.org/openwrt/trunk@12948 3c298f89-4303-0410-b956-a3cf2f4a3e73

22 files changed:
package/mac80211/patches/300-minstrel_no_mrr.patch [deleted file]
package/mac80211/patches/310-b43_txstatus.patch [deleted file]
package/mac80211/patches/407-debugfs-sta-work-fix.patch [new file with mode: 0644]
package/mac80211/patches/408-mac80211-remove-agg-debugfs.patch [new file with mode: 0644]
package/mac80211/patches/409-mac80211-remove-mesh-debugfs.patch [new file with mode: 0644]
package/mac80211/patches/410-mac80211-cleanups.patch [new file with mode: 0644]
package/mac80211/patches/411-mac80211-remove-wiphy-to-hw.patch [new file with mode: 0644]
package/mac80211/patches/412-mac80211-warn-ieee80211_hw_config-failure.patch [new file with mode: 0644]
package/mac80211/patches/413-mac80211-remove-antgain-cfg.patch [new file with mode: 0644]
package/mac80211/patches/414-mac80211-slot-time.patch [new file with mode: 0644]
package/mac80211/patches/415-mac80211-fix-exploit.patch [new file with mode: 0644]
package/mac80211/patches/416-mac80211-fix-netdev-notifier.patch [new file with mode: 0644]
package/mac80211/patches/417-cfg80211-fix-rename.patch [new file with mode: 0644]
package/mac80211/patches/418-ieee80211-cleanup-ht-terminology.patch [new file with mode: 0644]
package/mac80211/patches/419-mac80211-remove-antenna-sel.patch [new file with mode: 0644]
package/mac80211/patches/420-mac80211-hw-conf-change-flags.patch [new file with mode: 0644]
package/mac80211/patches/421-nl80211-export-ht.patch [new file with mode: 0644]
package/mac80211/patches/422-mac80211-seqno-station.patch [new file with mode: 0644]
package/mac80211/patches/423-mac80211-make-bss-conf-part-of-vif.patch [new file with mode: 0644]
package/mac80211/patches/424-mac80211-make-retry-limits-available.patch [new file with mode: 0644]
package/mac80211/patches/425-rewrite-rate-api.patch [new file with mode: 0644]
package/mac80211/patches/426-minstrel_performance.patch [new file with mode: 0644]

diff --git a/package/mac80211/patches/300-minstrel_no_mrr.patch b/package/mac80211/patches/300-minstrel_no_mrr.patch
deleted file mode 100644 (file)
index d4c04c4..0000000
+++ /dev/null
@@ -1,31 +0,0 @@
-This fixes tx status processing for drivers that do not support mrr.
-If the retry count is bigger than the maximum retry count configured in
-the hardware, do not count the rate attempt as successful, the hardware
-has probably switched to a lower rate.
-
-Signed-off-by: Felix Fietkau <nbd@openwrt.org>
-
---- a/net/mac80211/rc80211_minstrel.c
-+++ b/net/mac80211/rc80211_minstrel.c
-@@ -171,6 +171,7 @@ minstrel_tx_status(void *priv, struct ie
-       struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
-       struct ieee80211_tx_altrate *ar = info->status.retries;
-       struct minstrel_priv *mp = priv;
-+      struct ieee80211_local *local = hw_to_local(mp->hw);
-       int i, ndx, tries;
-       int success = 0;
-@@ -180,6 +181,13 @@ minstrel_tx_status(void *priv, struct ie
-       if (!mp->has_mrr || (ar[0].rate_idx < 0)) {
-               ndx = rix_to_ndx(mi, info->tx_rate_idx);
-               tries = info->status.retry_count + 1;
-+
-+              /* If the driver does not support the MRR API, but uses
-+               * a fallback rate, use the long retry limit as indication
-+               * that a rate switch has happened */
-+              if (!mp->has_mrr && (tries >= local->long_retry_limit))
-+                      success = 0;
-+
-               mi->r[ndx].success += success;
-               mi->r[ndx].attempts += tries;
-               return;
diff --git a/package/mac80211/patches/310-b43_txstatus.patch b/package/mac80211/patches/310-b43_txstatus.patch
deleted file mode 100644 (file)
index db731e5..0000000
+++ /dev/null
@@ -1,98 +0,0 @@
-Fix the b43 tx status reporting.
-
-If the hardware uses RTS/CTS reporting and the actual RTS/CTS
-handshake failed, it will switch to the fallback rate, even
-though the main rate was never actually attempted.
-Make sure that this does not screw up rate control statistics.
-
-Signed-off-by: Felix Fietkau <nbd@openwrt.org>
-
---- a/drivers/net/wireless/b43/b43.h
-+++ b/drivers/net/wireless/b43/b43.h
-@@ -778,6 +778,9 @@ struct b43_wldev {
- #ifdef CONFIG_B43_DEBUG
-       struct b43_dfsentry *dfsentry;
- #endif
-+
-+      /* necessary for figuring out the correct tx status */
-+      int short_retry;
- };
- static inline struct b43_wl *hw_to_b43_wl(struct ieee80211_hw *hw)
---- a/drivers/net/wireless/b43/dma.c
-+++ b/drivers/net/wireless/b43/dma.c
-@@ -1393,7 +1393,7 @@ void b43_dma_handle_txstatus(struct b43_
-                        * Call back to inform the ieee80211 subsystem about
-                        * the status of the transmission.
-                        */
--                      frame_succeed = b43_fill_txstatus_report(info, status);
-+                      frame_succeed = b43_fill_txstatus_report(dev, info, status);
- #ifdef CONFIG_B43_DEBUG
-                       if (frame_succeed)
-                               ring->nr_succeed_tx_packets++;
---- a/drivers/net/wireless/b43/main.c
-+++ b/drivers/net/wireless/b43/main.c
-@@ -3892,6 +3892,7 @@ static void b43_set_retry_limits(struct 
-                       short_retry);
-       b43_shm_write16(dev, B43_SHM_SCRATCH, B43_SHM_SC_LRLIMIT,
-                       long_retry);
-+      dev->short_retry = short_retry;
- }
- static void b43_set_synth_pu_delay(struct b43_wldev *dev, bool idle)
---- a/drivers/net/wireless/b43/pio.c
-+++ b/drivers/net/wireless/b43/pio.c
-@@ -589,7 +589,7 @@ void b43_pio_handle_txstatus(struct b43_
-       info = IEEE80211_SKB_CB(pack->skb);
-       memset(&info->status, 0, sizeof(info->status));
--      b43_fill_txstatus_report(info, status);
-+      b43_fill_txstatus_report(dev, info, status);
-       total_len = pack->skb->len + b43_txhdr_size(dev);
-       total_len = roundup(total_len, 4);
---- a/drivers/net/wireless/b43/xmit.c
-+++ b/drivers/net/wireless/b43/xmit.c
-@@ -687,7 +687,8 @@ void b43_handle_txstatus(struct b43_wlde
- /* Fill out the mac80211 TXstatus report based on the b43-specific
-  * txstatus report data. This returns a boolean whether the frame was
-  * successfully transmitted. */
--bool b43_fill_txstatus_report(struct ieee80211_tx_info *report,
-+bool b43_fill_txstatus_report(struct b43_wldev *dev,
-+                            struct ieee80211_tx_info *report,
-                             const struct b43_txstatus *status)
- {
-       bool frame_success = 1;
-@@ -706,8 +707,19 @@ bool b43_fill_txstatus_report(struct iee
-       if (status->frame_count == 0) {
-               /* The frame was not transmitted at all. */
-               report->status.retry_count = 0;
--      } else
-+      } else if (status->rts_count > dev->short_retry) {
-+              /*
-+               * If the short retries (RTS, not data frame) have exceeded
-+               * the limit, the hw will not have tried the selected rate,
-+               * but will have used the fallback rate instead.
-+               * Don't let the rate control count attempts for the selected
-+               * rate in this case, otherwise the statistics will be off.
-+               */
-+              report->tx_rate_idx = 0;
-+              report->status.retry_count = 0;
-+      } else {
-               report->status.retry_count = status->frame_count - 1;
-+      }
-       return frame_success;
- }
---- a/drivers/net/wireless/b43/xmit.h
-+++ b/drivers/net/wireless/b43/xmit.h
-@@ -294,7 +294,8 @@ void b43_rx(struct b43_wldev *dev, struc
- void b43_handle_txstatus(struct b43_wldev *dev,
-                        const struct b43_txstatus *status);
--bool b43_fill_txstatus_report(struct ieee80211_tx_info *report,
-+bool b43_fill_txstatus_report(struct b43_wldev *dev,
-+                            struct ieee80211_tx_info *report,
-                             const struct b43_txstatus *status);
- void b43_tx_suspend(struct b43_wldev *dev);
diff --git a/package/mac80211/patches/407-debugfs-sta-work-fix.patch b/package/mac80211/patches/407-debugfs-sta-work-fix.patch
new file mode 100644 (file)
index 0000000..4dbdba9
--- /dev/null
@@ -0,0 +1,68 @@
+Subject: mac80211: fix debugfs lockup
+
+When debugfs_create_dir fails, sta_info_debugfs_add_work will not
+terminate because it will find the same station again and again.
+This is possible whenever debugfs fails for whatever reason; one
+reason is a race condition in mac80211, unfortunately we cannot
+do much about it, so just document it, it just means some station
+may be missing from debugfs.
+
+Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
+Cc: Robin Holt <holt@sgi.com>
+---
+ net/mac80211/debugfs_sta.c |   11 +++++++++++
+ net/mac80211/sta_info.c    |    7 ++++++-
+ net/mac80211/sta_info.h    |    1 +
+ 3 files changed, 18 insertions(+), 1 deletion(-)
+
+--- everything.orig/net/mac80211/debugfs_sta.c 2008-10-07 20:05:29.000000000 +0200
++++ everything/net/mac80211/debugfs_sta.c      2008-10-07 20:06:39.000000000 +0200
+@@ -249,11 +249,22 @@ void ieee80211_sta_debugfs_add(struct st
+       DECLARE_MAC_BUF(mbuf);
+       u8 *mac;
++      sta->debugfs.add_has_run = true;
++
+       if (!stations_dir)
+               return;
+       mac = print_mac(mbuf, sta->sta.addr);
++      /*
++       * This might fail due to a race condition:
++       * When mac80211 unlinks a station, the debugfs entries
++       * remain, but it is already possible to link a new
++       * station with the same address which triggers adding
++       * it to debugfs; therefore, if the old station isn't
++       * destroyed quickly enough the old station's debugfs
++       * dir might still be around.
++       */
+       sta->debugfs.dir = debugfs_create_dir(mac, stations_dir);
+       if (!sta->debugfs.dir)
+               return;
+--- everything.orig/net/mac80211/sta_info.c    2008-10-07 20:05:29.000000000 +0200
++++ everything/net/mac80211/sta_info.c 2008-10-07 20:06:39.000000000 +0200
+@@ -635,7 +635,12 @@ static void sta_info_debugfs_add_work(st
+               spin_lock_irqsave(&local->sta_lock, flags);
+               list_for_each_entry(tmp, &local->sta_list, list) {
+-                      if (!tmp->debugfs.dir) {
++                      /*
++                       * debugfs.add_has_run will be set by
++                       * ieee80211_sta_debugfs_add regardless
++                       * of what else it does.
++                       */
++                      if (!tmp->debugfs.add_has_run) {
+                               sta = tmp;
+                               __sta_info_pin(sta);
+                               break;
+--- everything.orig/net/mac80211/sta_info.h    2008-10-07 20:05:29.000000000 +0200
++++ everything/net/mac80211/sta_info.h 2008-10-07 20:06:39.000000000 +0200
+@@ -300,6 +300,7 @@ struct sta_info {
+               struct dentry *inactive_ms;
+               struct dentry *last_seq_ctrl;
+               struct dentry *agg_status;
++              bool add_has_run;
+       } debugfs;
+ #endif
diff --git a/package/mac80211/patches/408-mac80211-remove-agg-debugfs.patch b/package/mac80211/patches/408-mac80211-remove-agg-debugfs.patch
new file mode 100644 (file)
index 0000000..5cbab68
--- /dev/null
@@ -0,0 +1,98 @@
+Subject: mac80211: remove aggregation status write support from debugfs
+
+This code uses static variables and thus cannot be kept.
+
+Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
+---
+ net/mac80211/debugfs_sta.c |   73 ---------------------------------------------
+ 1 file changed, 1 insertion(+), 72 deletions(-)
+
+--- everything.orig/net/mac80211/debugfs_sta.c 2008-10-07 20:06:39.000000000 +0200
++++ everything/net/mac80211/debugfs_sta.c      2008-10-07 20:06:40.000000000 +0200
+@@ -39,13 +39,6 @@ static const struct file_operations sta_
+       .open = mac80211_open_file_generic,                             \
+ }
+-#define STA_OPS_WR(name)                                              \
+-static const struct file_operations sta_ ##name## _ops = {            \
+-      .read = sta_##name##_read,                                      \
+-      .write = sta_##name##_write,                                    \
+-      .open = mac80211_open_file_generic,                             \
+-}
+-
+ #define STA_FILE(name, field, format)                                 \
+               STA_READ_##format(name, field)                          \
+               STA_OPS(name)
+@@ -168,71 +161,7 @@ static ssize_t sta_agg_status_read(struc
+       return simple_read_from_buffer(userbuf, count, ppos, buf, p - buf);
+ }
+-
+-static ssize_t sta_agg_status_write(struct file *file,
+-              const char __user *user_buf, size_t count, loff_t *ppos)
+-{
+-      struct sta_info *sta = file->private_data;
+-      struct ieee80211_local *local = sta->sdata->local;
+-      struct ieee80211_hw *hw = &local->hw;
+-      u8 *da = sta->sta.addr;
+-      static int tid_static_tx[16] = {0, 0, 0, 0, 0, 0, 0, 0,
+-                                      0, 0, 0, 0, 0, 0, 0, 0};
+-      static int tid_static_rx[16] = {1, 1, 1, 1, 1, 1, 1, 1,
+-                                      1, 1, 1, 1, 1, 1, 1, 1};
+-      char *endp;
+-      char buf[32];
+-      int buf_size, rs;
+-      unsigned int tid_num;
+-      char state[4];
+-
+-      memset(buf, 0x00, sizeof(buf));
+-      buf_size = min(count, (sizeof(buf)-1));
+-      if (copy_from_user(buf, user_buf, buf_size))
+-              return -EFAULT;
+-
+-      tid_num = simple_strtoul(buf, &endp, 0);
+-      if (endp == buf)
+-              return -EINVAL;
+-
+-      if ((tid_num >= 100) && (tid_num <= 115)) {
+-              /* toggle Rx aggregation command */
+-              tid_num = tid_num - 100;
+-              if (tid_static_rx[tid_num] == 1) {
+-                      strcpy(state, "off ");
+-                      ieee80211_sta_stop_rx_ba_session(sta->sdata, da, tid_num, 0,
+-                                      WLAN_REASON_QSTA_REQUIRE_SETUP);
+-                      sta->ampdu_mlme.tid_state_rx[tid_num] |=
+-                                      HT_AGG_STATE_DEBUGFS_CTL;
+-                      tid_static_rx[tid_num] = 0;
+-              } else {
+-                      strcpy(state, "on ");
+-                      sta->ampdu_mlme.tid_state_rx[tid_num] &=
+-                                      ~HT_AGG_STATE_DEBUGFS_CTL;
+-                      tid_static_rx[tid_num] = 1;
+-              }
+-              printk(KERN_DEBUG "debugfs - try switching tid %u %s\n",
+-                              tid_num, state);
+-      } else if ((tid_num >= 0) && (tid_num <= 15)) {
+-              /* toggle Tx aggregation command */
+-              if (tid_static_tx[tid_num] == 0) {
+-                      strcpy(state, "on ");
+-                      rs =  ieee80211_start_tx_ba_session(hw, da, tid_num);
+-                      if (rs == 0)
+-                              tid_static_tx[tid_num] = 1;
+-              } else {
+-                      strcpy(state, "off");
+-                      rs =  ieee80211_stop_tx_ba_session(hw, da, tid_num, 1);
+-                      if (rs == 0)
+-                              tid_static_tx[tid_num] = 0;
+-              }
+-              printk(KERN_DEBUG "debugfs - switching tid %u %s, return=%d\n",
+-                              tid_num, state, rs);
+-      }
+-
+-      return count;
+-}
+-STA_OPS_WR(agg_status);
++STA_OPS(agg_status);
+ #define DEBUGFS_ADD(name) \
+       sta->debugfs.name = debugfs_create_file(#name, 0400, \
diff --git a/package/mac80211/patches/409-mac80211-remove-mesh-debugfs.patch b/package/mac80211/patches/409-mac80211-remove-mesh-debugfs.patch
new file mode 100644 (file)
index 0000000..77c4701
--- /dev/null
@@ -0,0 +1,155 @@
+Subject: mac80211: remove writable debugs mesh parameters
+
+These parameters shouldn't be configurable via debugfs, if they
+need to be configurable nl80211 support has to be added, if not
+then they don't need to be writable here either.
+
+Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
+Cc: Javier Cardona <javier@cozybit.com>
+Cc: Luis Carlos Cobo <luisca@cozybit.com>
+---
+ net/mac80211/debugfs_netdev.c |  112 +++++++++---------------------------------
+ 1 file changed, 24 insertions(+), 88 deletions(-)
+
+--- everything.orig/net/mac80211/debugfs_netdev.c      2008-10-07 20:05:28.000000000 +0200
++++ everything/net/mac80211/debugfs_netdev.c   2008-10-07 20:06:40.000000000 +0200
+@@ -41,29 +41,6 @@ static ssize_t ieee80211_if_read(
+       return ret;
+ }
+-#ifdef CONFIG_MAC80211_MESH
+-static ssize_t ieee80211_if_write(
+-      struct ieee80211_sub_if_data *sdata,
+-      char const __user *userbuf,
+-      size_t count, loff_t *ppos,
+-      int (*format)(struct ieee80211_sub_if_data *, char *))
+-{
+-      char buf[10];
+-      int buf_size;
+-
+-      memset(buf, 0x00, sizeof(buf));
+-      buf_size = min(count, (sizeof(buf)-1));
+-      if (copy_from_user(buf, userbuf, buf_size))
+-              return count;
+-      read_lock(&dev_base_lock);
+-      if (sdata->dev->reg_state == NETREG_REGISTERED)
+-              (*format)(sdata, buf);
+-      read_unlock(&dev_base_lock);
+-
+-      return count;
+-}
+-#endif
+-
+ #define IEEE80211_IF_FMT(name, field, format_string)                  \
+ static ssize_t ieee80211_if_fmt_##name(                                       \
+       const struct ieee80211_sub_if_data *sdata, char *buf,           \
+@@ -71,19 +48,6 @@ static ssize_t ieee80211_if_fmt_##name(     
+ {                                                                     \
+       return scnprintf(buf, buflen, format_string, sdata->field);     \
+ }
+-#define IEEE80211_IF_WFMT(name, field, type)                          \
+-static int ieee80211_if_wfmt_##name(                                  \
+-      struct ieee80211_sub_if_data *sdata, char *buf)                 \
+-{                                                                     \
+-      unsigned long tmp;                                              \
+-      char *endp;                                                     \
+-                                                                      \
+-      tmp = simple_strtoul(buf, &endp, 0);                            \
+-      if ((endp == buf) || ((type)tmp != tmp))                        \
+-              return -EINVAL;                                         \
+-      sdata->field = tmp;                                             \
+-      return 0;                                                       \
+-}
+ #define IEEE80211_IF_FMT_DEC(name, field)                             \
+               IEEE80211_IF_FMT(name, field, "%d\n")
+ #define IEEE80211_IF_FMT_HEX(name, field)                             \
+@@ -126,34 +90,6 @@ static const struct file_operations name
+               IEEE80211_IF_FMT_##format(name, field)                  \
+               __IEEE80211_IF_FILE(name)
+-#define __IEEE80211_IF_WFILE(name)                                    \
+-static ssize_t ieee80211_if_read_##name(struct file *file,            \
+-                                      char __user *userbuf,           \
+-                                      size_t count, loff_t *ppos)     \
+-{                                                                     \
+-      return ieee80211_if_read(file->private_data,                    \
+-                               userbuf, count, ppos,                  \
+-                               ieee80211_if_fmt_##name);              \
+-}                                                                     \
+-static ssize_t ieee80211_if_write_##name(struct file *file,           \
+-                                      const char __user *userbuf,     \
+-                                      size_t count, loff_t *ppos)     \
+-{                                                                     \
+-      return ieee80211_if_write(file->private_data,                   \
+-                               userbuf, count, ppos,                  \
+-                               ieee80211_if_wfmt_##name);             \
+-}                                                                     \
+-static const struct file_operations name##_ops = {                    \
+-      .read = ieee80211_if_read_##name,                               \
+-      .write = ieee80211_if_write_##name,                             \
+-      .open = mac80211_open_file_generic,                             \
+-}
+-
+-#define IEEE80211_IF_WFILE(name, field, format, type)                 \
+-              IEEE80211_IF_FMT_##format(name, field)                  \
+-              IEEE80211_IF_WFMT(name, field, type)                    \
+-              __IEEE80211_IF_WFILE(name)
+-
+ /* common attributes */
+ IEEE80211_IF_FILE(drop_unencrypted, drop_unencrypted, DEC);
+ IEEE80211_IF_FILE(force_unicast_rateidx, force_unicast_rateidx, DEC);
+@@ -212,30 +148,30 @@ IEEE80211_IF_FILE(dropped_frames_no_rout
+ IEEE80211_IF_FILE(estab_plinks, u.mesh.mshstats.estab_plinks, ATOMIC);
+ /* Mesh parameters */
+-IEEE80211_IF_WFILE(dot11MeshMaxRetries,
+-              u.mesh.mshcfg.dot11MeshMaxRetries, DEC, u8);
+-IEEE80211_IF_WFILE(dot11MeshRetryTimeout,
+-              u.mesh.mshcfg.dot11MeshRetryTimeout, DEC, u16);
+-IEEE80211_IF_WFILE(dot11MeshConfirmTimeout,
+-              u.mesh.mshcfg.dot11MeshConfirmTimeout, DEC, u16);
+-IEEE80211_IF_WFILE(dot11MeshHoldingTimeout,
+-              u.mesh.mshcfg.dot11MeshHoldingTimeout, DEC, u16);
+-IEEE80211_IF_WFILE(dot11MeshTTL, u.mesh.mshcfg.dot11MeshTTL, DEC, u8);
+-IEEE80211_IF_WFILE(auto_open_plinks, u.mesh.mshcfg.auto_open_plinks, DEC, u8);
+-IEEE80211_IF_WFILE(dot11MeshMaxPeerLinks,
+-              u.mesh.mshcfg.dot11MeshMaxPeerLinks, DEC, u16);
+-IEEE80211_IF_WFILE(dot11MeshHWMPactivePathTimeout,
+-              u.mesh.mshcfg.dot11MeshHWMPactivePathTimeout, DEC, u32);
+-IEEE80211_IF_WFILE(dot11MeshHWMPpreqMinInterval,
+-              u.mesh.mshcfg.dot11MeshHWMPpreqMinInterval, DEC, u16);
+-IEEE80211_IF_WFILE(dot11MeshHWMPnetDiameterTraversalTime,
+-              u.mesh.mshcfg.dot11MeshHWMPnetDiameterTraversalTime, DEC, u16);
+-IEEE80211_IF_WFILE(dot11MeshHWMPmaxPREQretries,
+-              u.mesh.mshcfg.dot11MeshHWMPmaxPREQretries, DEC, u8);
+-IEEE80211_IF_WFILE(path_refresh_time,
+-              u.mesh.mshcfg.path_refresh_time, DEC, u32);
+-IEEE80211_IF_WFILE(min_discovery_timeout,
+-              u.mesh.mshcfg.min_discovery_timeout, DEC, u16);
++IEEE80211_IF_FILE(dot11MeshMaxRetries,
++              u.mesh.mshcfg.dot11MeshMaxRetries, DEC);
++IEEE80211_IF_FILE(dot11MeshRetryTimeout,
++              u.mesh.mshcfg.dot11MeshRetryTimeout, DEC);
++IEEE80211_IF_FILE(dot11MeshConfirmTimeout,
++              u.mesh.mshcfg.dot11MeshConfirmTimeout, DEC);
++IEEE80211_IF_FILE(dot11MeshHoldingTimeout,
++              u.mesh.mshcfg.dot11MeshHoldingTimeout, DEC);
++IEEE80211_IF_FILE(dot11MeshTTL, u.mesh.mshcfg.dot11MeshTTL, DEC);
++IEEE80211_IF_FILE(auto_open_plinks, u.mesh.mshcfg.auto_open_plinks, DEC);
++IEEE80211_IF_FILE(dot11MeshMaxPeerLinks,
++              u.mesh.mshcfg.dot11MeshMaxPeerLinks, DEC);
++IEEE80211_IF_FILE(dot11MeshHWMPactivePathTimeout,
++              u.mesh.mshcfg.dot11MeshHWMPactivePathTimeout, DEC);
++IEEE80211_IF_FILE(dot11MeshHWMPpreqMinInterval,
++              u.mesh.mshcfg.dot11MeshHWMPpreqMinInterval, DEC);
++IEEE80211_IF_FILE(dot11MeshHWMPnetDiameterTraversalTime,
++              u.mesh.mshcfg.dot11MeshHWMPnetDiameterTraversalTime, DEC);
++IEEE80211_IF_FILE(dot11MeshHWMPmaxPREQretries,
++              u.mesh.mshcfg.dot11MeshHWMPmaxPREQretries, DEC);
++IEEE80211_IF_FILE(path_refresh_time,
++              u.mesh.mshcfg.path_refresh_time, DEC);
++IEEE80211_IF_FILE(min_discovery_timeout,
++              u.mesh.mshcfg.min_discovery_timeout, DEC);
+ #endif
diff --git a/package/mac80211/patches/410-mac80211-cleanups.patch b/package/mac80211/patches/410-mac80211-cleanups.patch
new file mode 100644 (file)
index 0000000..bd66d04
--- /dev/null
@@ -0,0 +1,364 @@
+Subject: mac80211: minor code cleanups
+
+Nothing very interesting, some checkpatch inspired stuff,
+some other things.
+
+Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
+---
+ net/mac80211/debugfs_sta.c |    6 +++---
+ net/mac80211/main.c        |    2 +-
+ net/mac80211/mesh.c        |    2 +-
+ net/mac80211/rc80211_pid.h |    2 +-
+ net/mac80211/rx.c          |   24 +++++++++++++-----------
+ net/mac80211/sta_info.c    |    4 ++--
+ net/mac80211/wep.c         |   26 +++++++++++++-------------
+ net/mac80211/wep.h         |    2 +-
+ net/mac80211/wpa.c         |   29 ++++++++++-------------------
+ 9 files changed, 45 insertions(+), 52 deletions(-)
+
+--- everything.orig/net/mac80211/wep.c 2008-10-07 20:05:49.000000000 +0200
++++ everything/net/mac80211/wep.c      2008-10-07 20:06:41.000000000 +0200
+@@ -49,17 +49,19 @@ void ieee80211_wep_free(struct ieee80211
+       crypto_free_blkcipher(local->wep_rx_tfm);
+ }
+-static inline int ieee80211_wep_weak_iv(u32 iv, int keylen)
++static inline bool ieee80211_wep_weak_iv(u32 iv, int keylen)
+ {
+-      /* Fluhrer, Mantin, and Shamir have reported weaknesses in the
++      /*
++       * Fluhrer, Mantin, and Shamir have reported weaknesses in the
+        * key scheduling algorithm of RC4. At least IVs (KeyByte + 3,
+-       * 0xff, N) can be used to speedup attacks, so avoid using them. */
++       * 0xff, N) can be used to speedup attacks, so avoid using them.
++       */
+       if ((iv & 0xff00) == 0xff00) {
+               u8 B = (iv >> 16) & 0xff;
+               if (B >= 3 && B < 3 + keylen)
+-                      return 1;
++                      return true;
+       }
+-      return 0;
++      return false;
+ }
+@@ -268,7 +270,7 @@ int ieee80211_wep_decrypt(struct ieee802
+ }
+-u8 * ieee80211_wep_is_weak_iv(struct sk_buff *skb, struct ieee80211_key *key)
++bool ieee80211_wep_is_weak_iv(struct sk_buff *skb, struct ieee80211_key *key)
+ {
+       struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
+       unsigned int hdrlen;
+@@ -276,16 +278,13 @@ u8 * ieee80211_wep_is_weak_iv(struct sk_
+       u32 iv;
+       if (!ieee80211_has_protected(hdr->frame_control))
+-              return NULL;
++              return false;
+       hdrlen = ieee80211_hdrlen(hdr->frame_control);
+       ivpos = skb->data + hdrlen;
+       iv = (ivpos[0] << 16) | (ivpos[1] << 8) | ivpos[2];
+-      if (ieee80211_wep_weak_iv(iv, key->conf.keylen))
+-              return ivpos;
+-
+-      return NULL;
++      return ieee80211_wep_weak_iv(iv, key->conf.keylen);
+ }
+ ieee80211_rx_result
+@@ -329,6 +328,8 @@ static int wep_encrypt_skb(struct ieee80
+ ieee80211_tx_result
+ ieee80211_crypto_wep_encrypt(struct ieee80211_tx_data *tx)
+ {
++      int i;
++
+       ieee80211_tx_set_protected(tx);
+       if (wep_encrypt_skb(tx, tx->skb) < 0) {
+@@ -337,9 +338,8 @@ ieee80211_crypto_wep_encrypt(struct ieee
+       }
+       if (tx->extra_frag) {
+-              int i;
+               for (i = 0; i < tx->num_extra_frag; i++) {
+-                      if (wep_encrypt_skb(tx, tx->extra_frag[i]) < 0) {
++                      if (wep_encrypt_skb(tx, tx->extra_frag[i])) {
+                               I802_DEBUG_INC(tx->local->
+                                              tx_handlers_drop_wep);
+                               return TX_DROP;
+--- everything.orig/net/mac80211/wep.h 2008-10-07 20:05:28.000000000 +0200
++++ everything/net/mac80211/wep.h      2008-10-07 20:06:41.000000000 +0200
+@@ -26,7 +26,7 @@ int ieee80211_wep_encrypt(struct ieee802
+                         struct ieee80211_key *key);
+ int ieee80211_wep_decrypt(struct ieee80211_local *local, struct sk_buff *skb,
+                         struct ieee80211_key *key);
+-u8 *ieee80211_wep_is_weak_iv(struct sk_buff *skb, struct ieee80211_key *key);
++bool ieee80211_wep_is_weak_iv(struct sk_buff *skb, struct ieee80211_key *key);
+ ieee80211_rx_result
+ ieee80211_crypto_wep_decrypt(struct ieee80211_rx_data *rx);
+--- everything.orig/net/mac80211/wpa.c 2008-10-07 20:05:49.000000000 +0200
++++ everything/net/mac80211/wpa.c      2008-10-07 20:06:41.000000000 +0200
+@@ -49,8 +49,7 @@ ieee80211_tx_h_michael_mic_add(struct ie
+           !(tx->flags & IEEE80211_TX_FRAGMENTED) &&
+           !(tx->key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_MMIC) &&
+           !wpa_test) {
+-              /* hwaccel - with no need for preallocated room for Michael MIC
+-               */
++              /* hwaccel - with no need for preallocated room for MMIC */
+               return TX_CONTINUE;
+       }
+@@ -67,8 +66,6 @@ ieee80211_tx_h_michael_mic_add(struct ie
+ #else
+       authenticator = 1;
+ #endif
+-      /* At this point we know we're using ALG_TKIP. To get the MIC key
+-       * we now will rely on the offset from the ieee80211_key_conf::key */
+       key_offset = authenticator ?
+               NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY :
+               NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY;
+@@ -92,9 +89,7 @@ ieee80211_rx_h_michael_mic_verify(struct
+       int authenticator = 1, wpa_test = 0;
+       DECLARE_MAC_BUF(mac);
+-      /*
+-       * No way to verify the MIC if the hardware stripped it
+-       */
++      /* No way to verify the MIC if the hardware stripped it */
+       if (rx->status->flag & RX_FLAG_MMIC_STRIPPED)
+               return RX_CONTINUE;
+@@ -116,8 +111,6 @@ ieee80211_rx_h_michael_mic_verify(struct
+ #else
+       authenticator = 1;
+ #endif
+-      /* At this point we know we're using ALG_TKIP. To get the MIC key
+-       * we now will rely on the offset from the ieee80211_key_conf::key */
+       key_offset = authenticator ?
+               NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY :
+               NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY;
+@@ -202,6 +195,7 @@ ieee80211_tx_result
+ ieee80211_crypto_tkip_encrypt(struct ieee80211_tx_data *tx)
+ {
+       struct sk_buff *skb = tx->skb;
++      int i;
+       ieee80211_tx_set_protected(tx);
+@@ -209,9 +203,8 @@ ieee80211_crypto_tkip_encrypt(struct iee
+               return TX_DROP;
+       if (tx->extra_frag) {
+-              int i;
+               for (i = 0; i < tx->num_extra_frag; i++) {
+-                      if (tkip_encrypt_skb(tx, tx->extra_frag[i]) < 0)
++                      if (tkip_encrypt_skb(tx, tx->extra_frag[i]))
+                               return TX_DROP;
+               }
+       }
+@@ -350,7 +343,7 @@ static inline void ccmp_pn2hdr(u8 *hdr, 
+ }
+-static inline int ccmp_hdr2pn(u8 *pn, u8 *hdr)
++static inline void ccmp_hdr2pn(u8 *pn, u8 *hdr)
+ {
+       pn[0] = hdr[7];
+       pn[1] = hdr[6];
+@@ -358,7 +351,6 @@ static inline int ccmp_hdr2pn(u8 *pn, u8
+       pn[3] = hdr[4];
+       pn[4] = hdr[1];
+       pn[5] = hdr[0];
+-      return (hdr[3] >> 6) & 0x03;
+ }
+@@ -373,7 +365,7 @@ static int ccmp_encrypt_skb(struct ieee8
+       if ((tx->key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE) &&
+           !(tx->key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_IV)) {
+-              /* hwaccel - with no need for preallocated room for CCMP "
++              /* hwaccel - with no need for preallocated room for CCMP
+                * header or MIC fields */
+               info->control.hw_key = &tx->key->conf;
+               return 0;
+@@ -426,6 +418,7 @@ ieee80211_tx_result
+ ieee80211_crypto_ccmp_encrypt(struct ieee80211_tx_data *tx)
+ {
+       struct sk_buff *skb = tx->skb;
++      int i;
+       ieee80211_tx_set_protected(tx);
+@@ -433,9 +426,8 @@ ieee80211_crypto_ccmp_encrypt(struct iee
+               return TX_DROP;
+       if (tx->extra_frag) {
+-              int i;
+               for (i = 0; i < tx->num_extra_frag; i++) {
+-                      if (ccmp_encrypt_skb(tx, tx->extra_frag[i]) < 0)
++                      if (ccmp_encrypt_skb(tx, tx->extra_frag[i]))
+                               return TX_DROP;
+               }
+       }
+@@ -468,7 +460,7 @@ ieee80211_crypto_ccmp_decrypt(struct iee
+           (rx->status->flag & RX_FLAG_IV_STRIPPED))
+               return RX_CONTINUE;
+-      (void) ccmp_hdr2pn(pn, skb->data + hdrlen);
++      ccmp_hdr2pn(pn, skb->data + hdrlen);
+       if (memcmp(pn, key->u.ccmp.rx_pn[rx->queue], CCMP_PN_LEN) <= 0) {
+               key->u.ccmp.replays++;
+@@ -483,9 +475,8 @@ ieee80211_crypto_ccmp_decrypt(struct iee
+                           key->u.ccmp.tfm, key->u.ccmp.rx_crypto_buf,
+                           skb->data + hdrlen + CCMP_HDR_LEN, data_len,
+                           skb->data + skb->len - CCMP_MIC_LEN,
+-                          skb->data + hdrlen + CCMP_HDR_LEN)) {
++                          skb->data + hdrlen + CCMP_HDR_LEN))
+                       return RX_DROP_UNUSABLE;
+-              }
+       }
+       memcpy(key->u.ccmp.rx_pn[rx->queue], pn, CCMP_PN_LEN);
+--- everything.orig/net/mac80211/debugfs_sta.c 2008-10-07 20:06:40.000000000 +0200
++++ everything/net/mac80211/debugfs_sta.c      2008-10-07 20:06:41.000000000 +0200
+@@ -137,7 +137,7 @@ static ssize_t sta_agg_status_read(struc
+       p += scnprintf(p, sizeof(buf)+buf-p, "\n DTKN:");
+       for (i = 0; i < STA_TID_NUM; i++)
+               p += scnprintf(p, sizeof(buf)+buf-p, "%5d",
+-                      sta->ampdu_mlme.tid_state_rx[i]?
++                      sta->ampdu_mlme.tid_state_rx[i] ?
+                       sta->ampdu_mlme.tid_rx[i]->dialog_token : 0);
+       p += scnprintf(p, sizeof(buf)+buf-p, "\n TX  :");
+@@ -148,13 +148,13 @@ static ssize_t sta_agg_status_read(struc
+       p += scnprintf(p, sizeof(buf)+buf-p, "\n DTKN:");
+       for (i = 0; i < STA_TID_NUM; i++)
+               p += scnprintf(p, sizeof(buf)+buf-p, "%5d",
+-                      sta->ampdu_mlme.tid_state_tx[i]?
++                      sta->ampdu_mlme.tid_state_tx[i] ?
+                       sta->ampdu_mlme.tid_tx[i]->dialog_token : 0);
+       p += scnprintf(p, sizeof(buf)+buf-p, "\n SSN :");
+       for (i = 0; i < STA_TID_NUM; i++)
+               p += scnprintf(p, sizeof(buf)+buf-p, "%5d",
+-                      sta->ampdu_mlme.tid_state_tx[i]?
++                      sta->ampdu_mlme.tid_state_tx[i] ?
+                       sta->ampdu_mlme.tid_tx[i]->ssn : 0);
+       p += scnprintf(p, sizeof(buf)+buf-p, "\n");
+--- everything.orig/net/mac80211/main.c        2008-10-07 20:05:49.000000000 +0200
++++ everything/net/mac80211/main.c     2008-10-07 20:06:41.000000000 +0200
+@@ -1013,7 +1013,7 @@ static int __init ieee80211_init(void)
+       BUILD_BUG_ON(sizeof(struct ieee80211_tx_info) > sizeof(skb->cb));
+       BUILD_BUG_ON(offsetof(struct ieee80211_tx_info, driver_data) +
+-                   IEEE80211_TX_INFO_DRIVER_DATA_SIZE > sizeof(skb->cb));
++                   IEEE80211_TX_INFO_DRIVER_DATA_SIZE > sizeof(skb->cb));
+       ret = rc80211_minstrel_init();
+       if (ret)
+--- everything.orig/net/mac80211/mesh.c        2008-10-07 20:05:28.000000000 +0200
++++ everything/net/mac80211/mesh.c     2008-10-07 20:06:41.000000000 +0200
+@@ -473,7 +473,7 @@ static void ieee80211_mesh_rx_bcn_presp(
+                                       size_t len,
+                                       struct ieee80211_rx_status *rx_status)
+ {
+-      struct ieee80211_local *local= sdata->local;
++      struct ieee80211_local *local = sdata->local;
+       struct ieee802_11_elems elems;
+       struct ieee80211_channel *channel;
+       u64 supp_rates = 0;
+--- everything.orig/net/mac80211/rc80211_pid.h 2008-10-07 20:05:28.000000000 +0200
++++ everything/net/mac80211/rc80211_pid.h      2008-10-07 20:06:41.000000000 +0200
+@@ -49,7 +49,7 @@
+ /* Arithmetic right shift for positive and negative values for ISO C. */
+ #define RC_PID_DO_ARITH_RIGHT_SHIFT(x, y) \
+-      (x) < 0 ? -((-(x)) >> (y)) : (x) >> (y)
++      ((x) < 0 ? -((-(x)) >> (y)) : (x) >> (y))
+ enum rc_pid_event_type {
+       RC_PID_EVENT_TYPE_TX_STATUS,
+--- everything.orig/net/mac80211/rx.c  2008-10-07 20:06:38.000000000 +0200
++++ everything/net/mac80211/rx.c       2008-10-07 20:06:41.000000000 +0200
+@@ -26,10 +26,11 @@
+ #include "tkip.h"
+ #include "wme.h"
+-u8 ieee80211_sta_manage_reorder_buf(struct ieee80211_hw *hw,
+-                              struct tid_ampdu_rx *tid_agg_rx,
+-                              struct sk_buff *skb, u16 mpdu_seq_num,
+-                              int bar_req);
++static u8 ieee80211_sta_manage_reorder_buf(struct ieee80211_hw *hw,
++                                         struct tid_ampdu_rx *tid_agg_rx,
++                                         struct sk_buff *skb,
++                                         u16 mpdu_seq_num,
++                                         int bar_req);
+ /*
+  * monitor mode reception
+  *
+@@ -2000,17 +2001,17 @@ static void __ieee80211_rx_handle_packet
+ static inline int seq_less(u16 sq1, u16 sq2)
+ {
+-      return (((sq1 - sq2) & SEQ_MASK) > (SEQ_MODULO >> 1));
++      return ((sq1 - sq2) & SEQ_MASK) > (SEQ_MODULO >> 1);
+ }
+ static inline u16 seq_inc(u16 sq)
+ {
+-      return ((sq + 1) & SEQ_MASK);
++      return (sq + 1) & SEQ_MASK;
+ }
+ static inline u16 seq_sub(u16 sq1, u16 sq2)
+ {
+-      return ((sq1 - sq2) & SEQ_MASK);
++      return (sq1 - sq2) & SEQ_MASK;
+ }
+@@ -2018,10 +2019,11 @@ static inline u16 seq_sub(u16 sq1, u16 s
+  * As it function blongs to Rx path it must be called with
+  * the proper rcu_read_lock protection for its flow.
+  */
+-u8 ieee80211_sta_manage_reorder_buf(struct ieee80211_hw *hw,
+-                              struct tid_ampdu_rx *tid_agg_rx,
+-                              struct sk_buff *skb, u16 mpdu_seq_num,
+-                              int bar_req)
++static u8 ieee80211_sta_manage_reorder_buf(struct ieee80211_hw *hw,
++                                         struct tid_ampdu_rx *tid_agg_rx,
++                                         struct sk_buff *skb,
++                                         u16 mpdu_seq_num,
++                                         int bar_req)
+ {
+       struct ieee80211_local *local = hw_to_local(hw);
+       struct ieee80211_rx_status status;
+--- everything.orig/net/mac80211/sta_info.c    2008-10-07 20:06:39.000000000 +0200
++++ everything/net/mac80211/sta_info.c 2008-10-07 20:06:41.000000000 +0200
+@@ -294,7 +294,7 @@ int sta_info_insert(struct sta_info *sta
+       }
+       if (WARN_ON(compare_ether_addr(sta->sta.addr, sdata->dev->dev_addr) == 0 ||
+-                  is_multicast_ether_addr(sta->sta.addr))) {
++                  is_multicast_ether_addr(sta->sta.addr))) {
+               err = -EINVAL;
+               goto out_free;
+       }
+@@ -830,7 +830,7 @@ void ieee80211_sta_expire(struct ieee802
+ }
+ struct ieee80211_sta *ieee80211_find_sta(struct ieee80211_hw *hw,
+-                                         const u8 *addr)
++                                       const u8 *addr)
+ {
+       struct sta_info *sta = sta_info_get(hw_to_local(hw), addr);
diff --git a/package/mac80211/patches/411-mac80211-remove-wiphy-to-hw.patch b/package/mac80211/patches/411-mac80211-remove-wiphy-to-hw.patch
new file mode 100644 (file)
index 0000000..c8a1a22
--- /dev/null
@@ -0,0 +1,38 @@
+Subject: mac80211: remove wiphy_to_hw
+
+This isn't used by anyone, if we ever need it we can add
+it back, until then it's useless.
+
+Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
+---
+ include/net/mac80211.h |    2 --
+ net/mac80211/cfg.c     |    7 -------
+ 2 files changed, 9 deletions(-)
+
+--- everything.orig/include/net/mac80211.h     2008-10-07 20:05:49.000000000 +0200
++++ everything/include/net/mac80211.h  2008-10-07 20:06:42.000000000 +0200
+@@ -867,8 +867,6 @@ struct ieee80211_hw {
+       u8 max_altrate_tries;
+ };
+-struct ieee80211_hw *wiphy_to_hw(struct wiphy *wiphy);
+-
+ /**
+  * SET_IEEE80211_DEV - set device for 802.11 hardware
+  *
+--- everything.orig/net/mac80211/cfg.c 2008-10-07 20:06:37.000000000 +0200
++++ everything/net/mac80211/cfg.c      2008-10-07 20:06:42.000000000 +0200
+@@ -17,13 +17,6 @@
+ #include "rate.h"
+ #include "mesh.h"
+-struct ieee80211_hw *wiphy_to_hw(struct wiphy *wiphy)
+-{
+-      struct ieee80211_local *local = wiphy_priv(wiphy);
+-      return &local->hw;
+-}
+-EXPORT_SYMBOL(wiphy_to_hw);
+-
+ static bool nl80211_type_check(enum nl80211_iftype type)
+ {
+       switch (type) {
diff --git a/package/mac80211/patches/412-mac80211-warn-ieee80211_hw_config-failure.patch b/package/mac80211/patches/412-mac80211-warn-ieee80211_hw_config-failure.patch
new file mode 100644 (file)
index 0000000..f18569b
--- /dev/null
@@ -0,0 +1,113 @@
+Subject: mac80211: clean up ieee80211_hw_config errors
+
+Warn when ieee80211_hw_config returns an error, it shouldn't
+happen; remove a number of printks that would happen in such
+a case and one printk that is user-triggerable.
+
+Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
+---
+ net/mac80211/cfg.c  |    3 +--
+ net/mac80211/main.c |    8 +++++++-
+ net/mac80211/scan.c |   16 +++-------------
+ net/mac80211/util.c |    5 +----
+ net/mac80211/wext.c |    6 +-----
+ 5 files changed, 13 insertions(+), 25 deletions(-)
+
+--- everything.orig/net/mac80211/cfg.c 2008-10-07 20:06:42.000000000 +0200
++++ everything/net/mac80211/cfg.c      2008-10-07 20:06:43.000000000 +0200
+@@ -396,8 +396,7 @@ static int ieee80211_config_beacon(struc
+        */
+       if (params->interval) {
+               sdata->local->hw.conf.beacon_int = params->interval;
+-              if (ieee80211_hw_config(sdata->local))
+-                      return -EINVAL;
++              ieee80211_hw_config(sdata->local);
+               /*
+                * We updated some parameter so if below bails out
+                * it's not an error.
+--- everything.orig/net/mac80211/main.c        2008-10-07 20:06:41.000000000 +0200
++++ everything/net/mac80211/main.c     2008-10-07 20:06:43.000000000 +0200
+@@ -222,8 +222,14 @@ int ieee80211_hw_config(struct ieee80211
+              wiphy_name(local->hw.wiphy), chan->center_freq);
+ #endif
+-      if (local->open_count)
++      if (local->open_count) {
+               ret = local->ops->config(local_to_hw(local), &local->hw.conf);
++              /*
++               * HW reconfiguration should never fail, the driver has told
++               * us what it can support so it should live up to that promise.
++               */
++              WARN_ON(ret);
++      }
+       return ret;
+ }
+--- everything.orig/net/mac80211/scan.c        2008-10-07 20:05:27.000000000 +0200
++++ everything/net/mac80211/scan.c     2008-10-07 20:06:43.000000000 +0200
+@@ -447,18 +447,12 @@ void ieee80211_scan_completed(struct iee
+       if (local->hw_scanning) {
+               local->hw_scanning = false;
+-              if (ieee80211_hw_config(local))
+-                      printk(KERN_DEBUG "%s: failed to restore operational "
+-                             "channel after scan\n", wiphy_name(local->hw.wiphy));
+-
++              ieee80211_hw_config(local);
+               goto done;
+       }
+       local->sw_scanning = false;
+-      if (ieee80211_hw_config(local))
+-              printk(KERN_DEBUG "%s: failed to restore operational "
+-                     "channel after scan\n", wiphy_name(local->hw.wiphy));
+-
++      ieee80211_hw_config(local);
+       netif_tx_lock_bh(local->mdev);
+       netif_addr_lock(local->mdev);
+@@ -545,12 +539,8 @@ void ieee80211_scan_work(struct work_str
+               if (!skip) {
+                       local->scan_channel = chan;
+-                      if (ieee80211_hw_config(local)) {
+-                              printk(KERN_DEBUG "%s: failed to set freq to "
+-                                     "%d MHz for scan\n", wiphy_name(local->hw.wiphy),
+-                                     chan->center_freq);
++                      if (ieee80211_hw_config(local))
+                               skip = 1;
+-                      }
+               }
+               /* advance state machine to next channel/band */
+--- everything.orig/net/mac80211/util.c        2008-10-07 20:05:27.000000000 +0200
++++ everything/net/mac80211/util.c     2008-10-07 20:06:43.000000000 +0200
+@@ -638,11 +638,8 @@ int ieee80211_set_freq(struct ieee80211_
+       if (chan && !(chan->flags & IEEE80211_CHAN_DISABLED)) {
+               if (sdata->vif.type == NL80211_IFTYPE_ADHOC &&
+-                  chan->flags & IEEE80211_CHAN_NO_IBSS) {
+-                      printk(KERN_DEBUG "%s: IBSS not allowed on frequency "
+-                              "%d MHz\n", sdata->dev->name, chan->center_freq);
++                  chan->flags & IEEE80211_CHAN_NO_IBSS)
+                       return ret;
+-              }
+               local->oper_channel = chan;
+               if (local->sw_scanning || local->hw_scanning)
+--- everything.orig/net/mac80211/wext.c        2008-10-07 20:05:27.000000000 +0200
++++ everything/net/mac80211/wext.c     2008-10-07 20:06:43.000000000 +0200
+@@ -689,12 +689,8 @@ static int ieee80211_ioctl_siwtxpower(st
+               ieee80211_led_radio(local, local->hw.conf.radio_enabled);
+       }
+-      if (need_reconfig) {
++      if (need_reconfig)
+               ieee80211_hw_config(local);
+-              /* The return value of hw_config is not of big interest here,
+-               * as it doesn't say that it failed because of _this_ config
+-               * change or something else. Ignore it. */
+-      }
+       return 0;
+ }
diff --git a/package/mac80211/patches/413-mac80211-remove-antgain-cfg.patch b/package/mac80211/patches/413-mac80211-remove-antgain-cfg.patch
new file mode 100644 (file)
index 0000000..a7d8a95
--- /dev/null
@@ -0,0 +1,41 @@
+Subject: mac80211: remove max_antenna_gain config
+
+The antenna gain isn't exactly configurable, despite the belief of
+some unnamed individual who thinks that the EEPROM might influence
+it.
+
+Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
+---
+ include/net/mac80211.h |    2 --
+ net/mac80211/main.c    |    2 --
+ 2 files changed, 4 deletions(-)
+
+--- everything.orig/include/net/mac80211.h     2008-10-07 20:06:42.000000000 +0200
++++ everything/include/net/mac80211.h  2008-10-07 20:06:43.000000000 +0200
+@@ -470,7 +470,6 @@ enum ieee80211_conf_flags {
+  * @listen_interval: listen interval in units of beacon interval
+  * @flags: configuration flags defined above
+  * @power_level: requested transmit power (in dBm)
+- * @max_antenna_gain: maximum antenna gain (in dBi)
+  * @antenna_sel_tx: transmit antenna selection, 0: default/diversity,
+  *    1/2: antenna 0/1
+  * @antenna_sel_rx: receive antenna selection, like @antenna_sel_tx
+@@ -485,7 +484,6 @@ struct ieee80211_conf {
+       u16 listen_interval;
+       u32 flags;
+       int power_level;
+-      int max_antenna_gain;
+       u8 antenna_sel_tx;
+       u8 antenna_sel_rx;
+--- everything.orig/net/mac80211/main.c        2008-10-07 20:06:43.000000000 +0200
++++ everything/net/mac80211/main.c     2008-10-07 20:06:43.000000000 +0200
+@@ -215,8 +215,6 @@ int ieee80211_hw_config(struct ieee80211
+               local->hw.conf.power_level = min(chan->max_power,
+                                              local->hw.conf.power_level);
+-      local->hw.conf.max_antenna_gain = chan->max_antenna_gain;
+-
+ #ifdef CONFIG_MAC80211_VERBOSE_DEBUG
+       printk(KERN_DEBUG "%s: HW CONFIG: freq=%d\n",
+              wiphy_name(local->hw.wiphy), chan->center_freq);
diff --git a/package/mac80211/patches/414-mac80211-slot-time.patch b/package/mac80211/patches/414-mac80211-slot-time.patch
new file mode 100644 (file)
index 0000000..145e273
--- /dev/null
@@ -0,0 +1,201 @@
+Subject: mac80211: fix short slot handling
+
+This patch makes mac80211 handle short slot requests from the AP
+properly. Also warn about uses of IEEE80211_CONF_SHORT_SLOT_TIME
+and optimise out the code since it cannot ever be hit anyway.
+
+Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
+---
+ include/net/mac80211.h |   28 ++++++++++--------
+ net/mac80211/main.c    |    9 +++--
+ net/mac80211/mlme.c    |   74 ++++++++++++++++++++++++++-----------------------
+ 3 files changed, 62 insertions(+), 49 deletions(-)
+
+--- everything.orig/net/mac80211/main.c        2008-10-07 20:06:43.000000000 +0200
++++ everything/net/mac80211/main.c     2008-10-08 10:56:29.000000000 +0200
+@@ -346,9 +346,12 @@ void ieee80211_bss_info_change_notify(st
+ u32 ieee80211_reset_erp_info(struct ieee80211_sub_if_data *sdata)
+ {
+-      sdata->bss_conf.use_cts_prot = 0;
+-      sdata->bss_conf.use_short_preamble = 0;
+-      return BSS_CHANGED_ERP_CTS_PROT | BSS_CHANGED_ERP_PREAMBLE;
++      sdata->bss_conf.use_cts_prot = false;
++      sdata->bss_conf.use_short_preamble = false;
++      sdata->bss_conf.use_short_slot = false;
++      return BSS_CHANGED_ERP_CTS_PROT |
++             BSS_CHANGED_ERP_PREAMBLE |
++             BSS_CHANGED_ERP_SLOT;
+ }
+ void ieee80211_tx_status_irqsafe(struct ieee80211_hw *hw,
+--- everything.orig/net/mac80211/mlme.c        2008-10-07 20:05:49.000000000 +0200
++++ everything/net/mac80211/mlme.c     2008-10-08 10:56:38.000000000 +0200
+@@ -568,9 +568,8 @@ static void ieee80211_sta_wmm_params(str
+       }
+ }
+-static u32 ieee80211_handle_protect_preamb(struct ieee80211_sub_if_data *sdata,
+-                                         bool use_protection,
+-                                         bool use_short_preamble)
++static u32 ieee80211_handle_bss_capability(struct ieee80211_sub_if_data *sdata,
++                                         u16 capab, bool erp_valid, u8 erp)
+ {
+       struct ieee80211_bss_conf *bss_conf = &sdata->bss_conf;
+ #ifdef CONFIG_MAC80211_VERBOSE_DEBUG
+@@ -578,6 +577,19 @@ static u32 ieee80211_handle_protect_prea
+       DECLARE_MAC_BUF(mac);
+ #endif
+       u32 changed = 0;
++      bool use_protection;
++      bool use_short_preamble;
++      bool use_short_slot;
++
++      if (erp_valid) {
++              use_protection = (erp & WLAN_ERP_USE_PROTECTION) != 0;
++              use_short_preamble = (erp & WLAN_ERP_BARKER_PREAMBLE) == 0;
++      } else {
++              use_protection = false;
++              use_short_preamble = !!(capab & WLAN_CAPABILITY_SHORT_PREAMBLE);
++      }
++
++      use_short_slot = !!(capab & WLAN_CAPABILITY_SHORT_SLOT_TIME);
+       if (use_protection != bss_conf->use_cts_prot) {
+ #ifdef CONFIG_MAC80211_VERBOSE_DEBUG
+@@ -607,30 +619,18 @@ static u32 ieee80211_handle_protect_prea
+               changed |= BSS_CHANGED_ERP_PREAMBLE;
+       }
+-      return changed;
+-}
+-
+-static u32 ieee80211_handle_erp_ie(struct ieee80211_sub_if_data *sdata,
+-                                 u8 erp_value)
+-{
+-      bool use_protection = (erp_value & WLAN_ERP_USE_PROTECTION) != 0;
+-      bool use_short_preamble = (erp_value & WLAN_ERP_BARKER_PREAMBLE) == 0;
+-
+-      return ieee80211_handle_protect_preamb(sdata,
+-                      use_protection, use_short_preamble);
+-}
+-
+-static u32 ieee80211_handle_bss_capability(struct ieee80211_sub_if_data *sdata,
+-                                         struct ieee80211_bss *bss)
+-{
+-      u32 changed = 0;
+-
+-      if (bss->has_erp_value)
+-              changed |= ieee80211_handle_erp_ie(sdata, bss->erp_value);
+-      else {
+-              u16 capab = bss->capability;
+-              changed |= ieee80211_handle_protect_preamb(sdata, false,
+-                              (capab & WLAN_CAPABILITY_SHORT_PREAMBLE) != 0);
++      if (use_short_slot != bss_conf->use_short_slot) {
++#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
++              if (net_ratelimit()) {
++                      printk(KERN_DEBUG "%s: switched to %s slot"
++                             " (BSSID=%s)\n",
++                             sdata->dev->name,
++                             use_short_slot ? "short" : "long",
++                             print_mac(mac, ifsta->bssid));
++              }
++#endif
++              bss_conf->use_short_slot = use_short_slot;
++              changed |= BSS_CHANGED_ERP_SLOT;
+       }
+       return changed;
+@@ -723,7 +723,8 @@ static void ieee80211_set_associated(str
+               sdata->bss_conf.timestamp = bss->timestamp;
+               sdata->bss_conf.dtim_period = bss->dtim_period;
+-              changed |= ieee80211_handle_bss_capability(sdata, bss);
++              changed |= ieee80211_handle_bss_capability(sdata,
++                      bss->capability, bss->has_erp_value, bss->erp_value);
+               ieee80211_rx_bss_put(local, bss);
+       }
+@@ -1675,6 +1676,8 @@ static void ieee80211_rx_mgmt_beacon(str
+       struct ieee80211_local *local = sdata->local;
+       struct ieee80211_conf *conf = &local->hw.conf;
+       u32 changed = 0;
++      bool erp_valid;
++      u8 erp_value = 0;
+       /* Process beacon from the current BSS */
+       baselen = (u8 *) mgmt->u.beacon.variable - (u8 *) mgmt;
+@@ -1696,13 +1699,16 @@ static void ieee80211_rx_mgmt_beacon(str
+       ieee80211_sta_wmm_params(local, ifsta, elems.wmm_param,
+                                elems.wmm_param_len);
+-      if (elems.erp_info && elems.erp_info_len >= 1)
+-              changed |= ieee80211_handle_erp_ie(sdata, elems.erp_info[0]);
+-      else {
+-              u16 capab = le16_to_cpu(mgmt->u.beacon.capab_info);
+-              changed |= ieee80211_handle_protect_preamb(sdata, false,
+-                              (capab & WLAN_CAPABILITY_SHORT_PREAMBLE) != 0);
++
++      if (elems.erp_info && elems.erp_info_len >= 1) {
++              erp_valid = true;
++              erp_value = elems.erp_info[0];
++      } else {
++              erp_valid = false;
+       }
++      changed |= ieee80211_handle_bss_capability(sdata,
++                      le16_to_cpu(mgmt->u.beacon.capab_info),
++                      erp_valid, erp_value);
+       if (elems.ht_cap_elem && elems.ht_info_elem &&
+           elems.wmm_param && conf->flags & IEEE80211_CONF_SUPPORT_HT_MODE) {
+--- everything.orig/include/net/mac80211.h     2008-10-07 20:06:43.000000000 +0200
++++ everything/include/net/mac80211.h  2008-10-08 10:57:06.000000000 +0200
+@@ -180,8 +180,12 @@ enum ieee80211_bss_change {
+  * @assoc: association status
+  * @aid: association ID number, valid only when @assoc is true
+  * @use_cts_prot: use CTS protection
+- * @use_short_preamble: use 802.11b short preamble
+- * @use_short_slot: use short slot time (only relevant for ERP)
++ * @use_short_preamble: use 802.11b short preamble;
++ *    if the hardware cannot handle this it must set the
++ *    IEEE80211_HW_2GHZ_SHORT_PREAMBLE_INCAPABLE hardware flag
++ * @use_short_slot: use short slot time (only relevant for ERP);
++ *    if the hardware cannot handle this it must set the
++ *    IEEE80211_HW_2GHZ_SHORT_SLOT_INCAPABLE hardware flag
+  * @dtim_period: num of beacons before the next DTIM, for PSM
+  * @timestamp: beacon timestamp
+  * @beacon_int: beacon interval
+@@ -442,23 +446,23 @@ struct ieee80211_rx_status {
+  *
+  * Flags to define PHY configuration options
+  *
+- * @IEEE80211_CONF_SHORT_SLOT_TIME: use 802.11g short slot time
+  * @IEEE80211_CONF_RADIOTAP: add radiotap header at receive time (if supported)
+  * @IEEE80211_CONF_SUPPORT_HT_MODE: use 802.11n HT capabilities (if supported)
+  * @IEEE80211_CONF_PS: Enable 802.11 power save mode
+  */
+ enum ieee80211_conf_flags {
+-      /*
+-       * TODO: IEEE80211_CONF_SHORT_SLOT_TIME will be removed once drivers
+-       * have been converted to use bss_info_changed() for slot time
+-       * configuration
+-       */
+-      IEEE80211_CONF_SHORT_SLOT_TIME  = (1<<0),
+-      IEEE80211_CONF_RADIOTAP         = (1<<1),
+-      IEEE80211_CONF_SUPPORT_HT_MODE  = (1<<2),
+-      IEEE80211_CONF_PS               = (1<<3),
++      IEEE80211_CONF_RADIOTAP         = (1<<0),
++      IEEE80211_CONF_SUPPORT_HT_MODE  = (1<<1),
++      IEEE80211_CONF_PS               = (1<<2),
+ };
++/* XXX: remove all this once drivers stop trying to use it */
++static inline int __deprecated __IEEE80211_CONF_SHORT_SLOT_TIME(void)
++{
++      return 0;
++}
++#define IEEE80211_CONF_SHORT_SLOT_TIME (__IEEE80211_CONF_SHORT_SLOT_TIME())
++
+ /**
+  * struct ieee80211_conf - configuration of the device
+  *
diff --git a/package/mac80211/patches/415-mac80211-fix-exploit.patch b/package/mac80211/patches/415-mac80211-fix-exploit.patch
new file mode 100644 (file)
index 0000000..114c943
--- /dev/null
@@ -0,0 +1,77 @@
+Subject: mac80211: fix HT information element parsing
+
+There's no checking that the HT IEs are of the right length
+which can be used by an attacker to cause an out-of-bounds
+access by sending a too short HT information/capability IE.
+Fix it by simply pretending those IEs didn't exist when too
+short.
+
+Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
+---
+ net/mac80211/ieee80211_i.h |    6 ++----
+ net/mac80211/mlme.c        |    3 ---
+ net/mac80211/util.c        |    8 ++++----
+ 3 files changed, 6 insertions(+), 11 deletions(-)
+
+--- everything.orig/net/mac80211/ieee80211_i.h 2008-10-07 20:05:26.000000000 +0200
++++ everything/net/mac80211/ieee80211_i.h      2008-10-07 20:06:45.000000000 +0200
+@@ -816,8 +816,8 @@ struct ieee802_11_elems {
+       u8 *ext_supp_rates;
+       u8 *wmm_info;
+       u8 *wmm_param;
+-      u8 *ht_cap_elem;
+-      u8 *ht_info_elem;
++      struct ieee80211_ht_cap *ht_cap_elem;
++      struct ieee80211_ht_addt_info *ht_info_elem;
+       u8 *mesh_config;
+       u8 *mesh_id;
+       u8 *peer_link;
+@@ -844,8 +844,6 @@ struct ieee802_11_elems {
+       u8 ext_supp_rates_len;
+       u8 wmm_info_len;
+       u8 wmm_param_len;
+-      u8 ht_cap_elem_len;
+-      u8 ht_info_elem_len;
+       u8 mesh_config_len;
+       u8 mesh_id_len;
+       u8 peer_link_len;
+--- everything.orig/net/mac80211/mlme.c        2008-10-07 20:06:44.000000000 +0200
++++ everything/net/mac80211/mlme.c     2008-10-07 20:06:45.000000000 +0200
+@@ -1349,10 +1349,8 @@ static void ieee80211_rx_mgmt_assoc_resp
+           (ifsta->flags & IEEE80211_STA_WMM_ENABLED)) {
+               struct ieee80211_ht_bss_info bss_info;
+               ieee80211_ht_cap_ie_to_ht_info(
+-                              (struct ieee80211_ht_cap *)
+                               elems.ht_cap_elem, &sta->sta.ht_info);
+               ieee80211_ht_addt_info_ie_to_ht_bss_info(
+-                              (struct ieee80211_ht_addt_info *)
+                               elems.ht_info_elem, &bss_info);
+               ieee80211_handle_ht(local, 1, &sta->sta.ht_info, &bss_info);
+       }
+@@ -1715,7 +1713,6 @@ static void ieee80211_rx_mgmt_beacon(str
+               struct ieee80211_ht_bss_info bss_info;
+               ieee80211_ht_addt_info_ie_to_ht_bss_info(
+-                              (struct ieee80211_ht_addt_info *)
+                               elems.ht_info_elem, &bss_info);
+               changed |= ieee80211_handle_ht(local, 1, &conf->ht_conf,
+                                              &bss_info);
+--- everything.orig/net/mac80211/util.c        2008-10-07 20:06:43.000000000 +0200
++++ everything/net/mac80211/util.c     2008-10-07 20:06:45.000000000 +0200
+@@ -529,12 +529,12 @@ void ieee802_11_parse_elems(u8 *start, s
+                       elems->ext_supp_rates_len = elen;
+                       break;
+               case WLAN_EID_HT_CAPABILITY:
+-                      elems->ht_cap_elem = pos;
+-                      elems->ht_cap_elem_len = elen;
++                      if (elen >= sizeof(struct ieee80211_ht_cap))
++                              elems->ht_cap_elem = (void *)pos;
+                       break;
+               case WLAN_EID_HT_EXTRA_INFO:
+-                      elems->ht_info_elem = pos;
+-                      elems->ht_info_elem_len = elen;
++                      if (elen >= sizeof(struct ieee80211_ht_addt_info))
++                              elems->ht_info_elem = (void *)pos;
+                       break;
+               case WLAN_EID_MESH_ID:
+                       elems->mesh_id = pos;
diff --git a/package/mac80211/patches/416-mac80211-fix-netdev-notifier.patch b/package/mac80211/patches/416-mac80211-fix-netdev-notifier.patch
new file mode 100644 (file)
index 0000000..aee4582
--- /dev/null
@@ -0,0 +1,27 @@
+Subject: mac80211: fix debugfs netdev rename
+
+If, for some reason, a netdev has no debugfs dir, we shouldn't
+try to rename that dir.
+
+Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
+Cc: Robin Holt <holt@sgi.com>
+---
+ net/mac80211/debugfs_netdev.c |    6 +++++-
+ 1 file changed, 5 insertions(+), 1 deletion(-)
+
+--- everything.orig/net/mac80211/debugfs_netdev.c      2008-10-08 10:08:23.000000000 +0200
++++ everything/net/mac80211/debugfs_netdev.c   2008-10-08 10:22:52.000000000 +0200
+@@ -481,8 +481,12 @@ static int netdev_notify(struct notifier
+       sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+-      sprintf(buf, "netdev:%s", dev->name);
+       dir = sdata->debugfsdir;
++
++      if (!dir)
++              return 0;
++
++      sprintf(buf, "netdev:%s", dev->name);
+       if (!debugfs_rename(dir->d_parent, dir, dir->d_parent, buf))
+               printk(KERN_ERR "mac80211: debugfs: failed to rename debugfs "
+                      "dir to %s\n", buf);
diff --git a/package/mac80211/patches/417-cfg80211-fix-rename.patch b/package/mac80211/patches/417-cfg80211-fix-rename.patch
new file mode 100644 (file)
index 0000000..3cfab61
--- /dev/null
@@ -0,0 +1,32 @@
+Subject: cfg80211: fix debugfs error handling
+
+If something goes wrong creating the debugfs dir or when
+debugfs is not compiled in, the current code might lead to
+trouble; make it more robust.
+
+Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
+---
+ net/wireless/core.c |    5 ++++-
+ 1 file changed, 4 insertions(+), 1 deletion(-)
+
+--- everything.orig/net/wireless/core.c        2008-10-08 10:13:49.000000000 +0200
++++ everything/net/wireless/core.c     2008-10-08 10:19:10.000000000 +0200
+@@ -185,7 +185,8 @@ int cfg80211_dev_rename(struct cfg80211_
+       if (result)
+               goto out_unlock;
+-      if (!debugfs_rename(rdev->wiphy.debugfsdir->d_parent,
++      if (rdev->wiphy.debugfsdir &&
++          !debugfs_rename(rdev->wiphy.debugfsdir->d_parent,
+                           rdev->wiphy.debugfsdir,
+                           rdev->wiphy.debugfsdir->d_parent,
+                           newname))
+@@ -318,6 +319,8 @@ int wiphy_register(struct wiphy *wiphy)
+       drv->wiphy.debugfsdir =
+               debugfs_create_dir(wiphy_name(&drv->wiphy),
+                                  ieee80211_debugfs_dir);
++      if (IS_ERR(drv->wiphy.debugfsdir))
++              drv->wiphy.debugfsdir = NULL;
+       res = 0;
+ out_unlock:
diff --git a/package/mac80211/patches/418-ieee80211-cleanup-ht-terminology.patch b/package/mac80211/patches/418-ieee80211-cleanup-ht-terminology.patch
new file mode 100644 (file)
index 0000000..61ae15a
--- /dev/null
@@ -0,0 +1,1427 @@
+Subject: 802.11: clean up/fix HT support
+
+This patch cleans up a number of things:
+ * the unusable definition of the HT capabilities/HT information
+   information elements
+ * variable names that are hard to understand
+ * mac80211: move ieee80211_handle_ht to ht.c and remove the unused
+             enable_ht parameter
+ * mac80211: fix bug with MCS rate 32 in ieee80211_handle_ht
+ * mac80211: fix bug with casting the result of ieee80211_bss_get_ie
+             to an information element _contents_ rather than the
+             whole element, add size checking (another out-of-bounds
+             access bug fixed!)
+ * mac80211: remove some unused return values in favour of BUG_ON
+             checking
+ * a few minor other things
+
+Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
+---
+ drivers/net/wireless/ath9k/main.c         |   57 +++++------
+ drivers/net/wireless/ath9k/rc.c           |   10 -
+ drivers/net/wireless/ath9k/rc.h           |    1 
+ drivers/net/wireless/ath9k/recv.c         |    2 
+ drivers/net/wireless/ath9k/xmit.c         |    2 
+ drivers/net/wireless/iwlwifi/iwl-agn-rs.c |   18 +--
+ drivers/net/wireless/iwlwifi/iwl-agn.c    |   20 +--
+ drivers/net/wireless/iwlwifi/iwl-core.c   |   71 +++++++-------
+ drivers/net/wireless/iwlwifi/iwl-core.h   |    2 
+ drivers/net/wireless/iwlwifi/iwl-dev.h    |    4 
+ drivers/net/wireless/iwlwifi/iwl-scan.c   |   12 +-
+ drivers/net/wireless/iwlwifi/iwl-sta.c    |    6 -
+ drivers/net/wireless/mac80211_hwsim.c     |   19 +--
+ include/linux/ieee80211.h                 |  133 ++++++++++++++++++--------
+ include/net/mac80211.h                    |   12 +-
+ include/net/wireless.h                    |   15 +-
+ net/mac80211/cfg.c                        |    7 -
+ net/mac80211/ht.c                         |  151 +++++++++++++++++++++++++-----
+ net/mac80211/ieee80211_i.h                |   16 +--
+ net/mac80211/main.c                       |   94 ------------------
+ net/mac80211/mlme.c                       |   45 ++++----
+ net/mac80211/util.c                       |    4 
+ net/mac80211/wext.c                       |    4 
+ 23 files changed, 386 insertions(+), 319 deletions(-)
+
+--- everything.orig/include/linux/ieee80211.h  2008-10-08 20:44:47.000000000 +0200
++++ everything/include/linux/ieee80211.h       2008-10-09 02:16:21.000000000 +0200
+@@ -685,28 +685,88 @@ struct ieee80211_bar {
+ #define IEEE80211_BAR_CTRL_ACK_POLICY_NORMAL     0x0000
+ #define IEEE80211_BAR_CTRL_CBMTID_COMPRESSED_BA  0x0004
++
++#define IEEE80211_HT_MCS_MASK_LEN             10
++
++/**
++ * struct ieee80211_mcs_info - MCS information
++ * @rx_mask: RX mask
++ * @rx_highest: highest supported RX rate
++ * @tx_params: TX parameters
++ */
++struct ieee80211_mcs_info {
++      u8 rx_mask[IEEE80211_HT_MCS_MASK_LEN];
++      __le16 rx_highest;
++      u8 tx_params;
++      u8 reserved[3];
++} __attribute__((packed));
++
++/* 802.11n HT capability MSC set */
++#define IEEE80211_HT_MCS_RX_HIGHEST_MASK      0x3ff
++#define IEEE80211_HT_MCS_TX_DEFINED           0x01
++#define IEEE80211_HT_MCS_TX_RX_DIFF           0x02
++/* value 0 == 1 stream etc */
++#define IEEE80211_HT_MCS_TX_MAX_STREAMS_MASK  0x0C
++#define IEEE80211_HT_MCS_TX_MAX_STREAMS_SHIFT 2
++#define               IEEE80211_HT_MCS_TX_MAX_STREAMS 4
++#define IEEE80211_HT_MCS_TX_UNEQUAL_MODULATION        0x10
++
++/*
++ * 802.11n D5.0 20.3.5 / 20.6 says:
++ * - indices 0 to 7 and 32 are single spatial stream
++ * - 8 to 31 are multiple spatial streams using equal modulation
++ *   [8..15 for two streams, 16..23 for three and 24..31 for four]
++ * - remainder are multiple spatial streams using unequal modulation
++ */
++#define IEEE80211_HT_MCS_UNEQUAL_MODULATION_START 33
++#define IEEE80211_HT_MCS_UNEQUAL_MODULATION_START_BYTE \
++      (IEEE80211_HT_MCS_UNEQUAL_MODULATION_START / 8)
++
+ /**
+  * struct ieee80211_ht_cap - HT capabilities
+  *
+- * This structure refers to "HT capabilities element" as
+- * described in 802.11n draft section 7.3.2.52
++ * This structure is the "HT capabilities element" as
++ * described in 802.11n D5.0 7.3.2.57
+  */
+ struct ieee80211_ht_cap {
+       __le16 cap_info;
+       u8 ampdu_params_info;
+-      u8 supp_mcs_set[16];
++
++      /* 16 bytes MCS information */
++      struct ieee80211_mcs_info mcs;
++
+       __le16 extended_ht_cap_info;
+       __le32 tx_BF_cap_info;
+       u8 antenna_selection_info;
+ } __attribute__ ((packed));
++/* 802.11n HT capabilities masks (for cap_info) */
++#define IEEE80211_HT_CAP_LDPC_CODING          0x0001
++#define IEEE80211_HT_CAP_SUP_WIDTH_20_40      0x0002
++#define IEEE80211_HT_CAP_SM_PS                        0x000C
++#define IEEE80211_HT_CAP_GRN_FLD              0x0010
++#define IEEE80211_HT_CAP_SGI_20                       0x0020
++#define IEEE80211_HT_CAP_SGI_40                       0x0040
++#define IEEE80211_HT_CAP_TX_STBC              0x0080
++#define IEEE80211_HT_CAP_RX_STBC              0x0300
++#define IEEE80211_HT_CAP_DELAY_BA             0x0400
++#define IEEE80211_HT_CAP_MAX_AMSDU            0x0800
++#define IEEE80211_HT_CAP_DSSSCCK40            0x1000
++#define IEEE80211_HT_CAP_PSMP_SUPPORT         0x2000
++#define IEEE80211_HT_CAP_40MHZ_INTOLERANT     0x4000
++#define IEEE80211_HT_CAP_LSIG_TXOP_PROT               0x8000
++
++/* 802.11n HT capability AMPDU settings (for ampdu_params_info) */
++#define IEEE80211_HT_AMPDU_PARM_FACTOR                0x03
++#define IEEE80211_HT_AMPDU_PARM_DENSITY               0x1C
++
+ /**
+- * struct ieee80211_ht_cap - HT additional information
++ * struct ieee80211_ht_info - HT information
+  *
+- * This structure refers to "HT information element" as
+- * described in 802.11n draft section 7.3.2.53
++ * This structure is the "HT information element" as
++ * described in 802.11n D5.0 7.3.2.58
+  */
+-struct ieee80211_ht_addt_info {
++struct ieee80211_ht_info {
+       u8 control_chan;
+       u8 ht_param;
+       __le16 operation_mode;
+@@ -714,36 +774,33 @@ struct ieee80211_ht_addt_info {
+       u8 basic_set[16];
+ } __attribute__ ((packed));
+-/* 802.11n HT capabilities masks */
+-#define IEEE80211_HT_CAP_SUP_WIDTH            0x0002
+-#define IEEE80211_HT_CAP_SM_PS                        0x000C
+-#define IEEE80211_HT_CAP_GRN_FLD              0x0010
+-#define IEEE80211_HT_CAP_SGI_20                       0x0020
+-#define IEEE80211_HT_CAP_SGI_40                       0x0040
+-#define IEEE80211_HT_CAP_DELAY_BA             0x0400
+-#define IEEE80211_HT_CAP_MAX_AMSDU            0x0800
+-#define IEEE80211_HT_CAP_DSSSCCK40            0x1000
+-/* 802.11n HT capability AMPDU settings */
+-#define IEEE80211_HT_CAP_AMPDU_FACTOR         0x03
+-#define IEEE80211_HT_CAP_AMPDU_DENSITY                0x1C
+-/* 802.11n HT capability MSC set */
+-#define IEEE80211_SUPP_MCS_SET_UEQM           4
+-#define IEEE80211_HT_CAP_MAX_STREAMS          4
+-#define IEEE80211_SUPP_MCS_SET_LEN            10
+-/* maximum streams the spec allows */
+-#define IEEE80211_HT_CAP_MCS_TX_DEFINED               0x01
+-#define IEEE80211_HT_CAP_MCS_TX_RX_DIFF               0x02
+-#define IEEE80211_HT_CAP_MCS_TX_STREAMS               0x0C
+-#define IEEE80211_HT_CAP_MCS_TX_UEQM          0x10
+-/* 802.11n HT IE masks */
+-#define IEEE80211_HT_IE_CHA_SEC_OFFSET                0x03
+-#define IEEE80211_HT_IE_CHA_SEC_NONE          0x00
+-#define IEEE80211_HT_IE_CHA_SEC_ABOVE                 0x01
+-#define IEEE80211_HT_IE_CHA_SEC_BELOW                 0x03
+-#define IEEE80211_HT_IE_CHA_WIDTH             0x04
+-#define IEEE80211_HT_IE_HT_PROTECTION         0x0003
+-#define IEEE80211_HT_IE_NON_GF_STA_PRSNT      0x0004
+-#define IEEE80211_HT_IE_NON_HT_STA_PRSNT      0x0010
++/* for ht_param */
++#define IEEE80211_HT_PARAM_CHA_SEC_OFFSET             0x03
++#define               IEEE80211_HT_PARAM_CHA_SEC_NONE         0x00
++#define               IEEE80211_HT_PARAM_CHA_SEC_ABOVE        0x01
++#define               IEEE80211_HT_PARAM_CHA_SEC_BELOW        0x03
++#define IEEE80211_HT_PARAM_CHAN_WIDTH_ANY             0x04
++#define IEEE80211_HT_PARAM_RIFS_MODE                  0x08
++#define IEEE80211_HT_PARAM_SPSMP_SUPPORT              0x10
++#define IEEE80211_HT_PARAM_SERV_INTERVAL_GRAN         0xE0
++
++/* for operation_mode */
++#define IEEE80211_HT_OP_MODE_PROTECTION                       0x0003
++#define               IEEE80211_HT_OP_MODE_PROTECTION_NONE            0
++#define               IEEE80211_HT_OP_MODE_PROTECTION_NONMEMBER       1
++#define               IEEE80211_HT_OP_MODE_PROTECTION_20MHZ           2
++#define               IEEE80211_HT_OP_MODE_PROTECTION_NONHT_MIXED     3
++#define IEEE80211_HT_OP_MODE_NON_GF_STA_PRSNT         0x0004
++#define IEEE80211_HT_OP_MODE_NON_HT_STA_PRSNT         0x0010
++
++/* for stbc_param */
++#define IEEE80211_HT_STBC_PARAM_DUAL_BEACON           0x0040
++#define IEEE80211_HT_STBC_PARAM_DUAL_CTS_PROT         0x0080
++#define IEEE80211_HT_STBC_PARAM_STBC_BEACON           0x0100
++#define IEEE80211_HT_STBC_PARAM_LSIG_TXOP_FULLPROT    0x0200
++#define IEEE80211_HT_STBC_PARAM_PCO_ACTIVE            0x0400
++#define IEEE80211_HT_STBC_PARAM_PCO_PHASE             0x0800
++
+ /* block-ack parameters */
+ #define IEEE80211_ADDBA_PARAM_POLICY_MASK 0x0002
+@@ -949,7 +1006,7 @@ enum ieee80211_eid {
+       WLAN_EID_EXT_SUPP_RATES = 50,
+       /* 802.11n */
+       WLAN_EID_HT_CAPABILITY = 45,
+-      WLAN_EID_HT_EXTRA_INFO = 61,
++      WLAN_EID_HT_INFORMATION = 61,
+       /* 802.11i */
+       WLAN_EID_RSN = 48,
+       WLAN_EID_WPA = 221,
+--- everything.orig/include/net/wireless.h     2008-10-08 20:44:46.000000000 +0200
++++ everything/include/net/wireless.h  2008-10-09 02:16:20.000000000 +0200
+@@ -10,6 +10,7 @@
+ #include <linux/netdevice.h>
+ #include <linux/debugfs.h>
+ #include <linux/list.h>
++#include <linux/ieee80211.h>
+ #include <net/cfg80211.h>
+ /**
+@@ -133,23 +134,23 @@ struct ieee80211_rate {
+ };
+ /**
+- * struct ieee80211_ht_info - describing STA's HT capabilities
++ * struct ieee80211_sta_ht_cap - STA's HT capabilities
+  *
+  * This structure describes most essential parameters needed
+  * to describe 802.11n HT capabilities for an STA.
+  *
+- * @ht_supported: is HT supported by STA, 0: no, 1: yes
++ * @ht_supported: is HT supported by the STA
+  * @cap: HT capabilities map as described in 802.11n spec
+  * @ampdu_factor: Maximum A-MPDU length factor
+  * @ampdu_density: Minimum A-MPDU spacing
+- * @supp_mcs_set: Supported MCS set as described in 802.11n spec
++ * @mcs: Supported MCS rates
+  */
+-struct ieee80211_ht_info {
++struct ieee80211_sta_ht_cap {
+       u16 cap; /* use IEEE80211_HT_CAP_ */
+-      u8 ht_supported;
++      bool ht_supported;
+       u8 ampdu_factor;
+       u8 ampdu_density;
+-      u8 supp_mcs_set[16];
++      struct ieee80211_mcs_info mcs;
+ };
+ /**
+@@ -173,7 +174,7 @@ struct ieee80211_supported_band {
+       enum ieee80211_band band;
+       int n_channels;
+       int n_bitrates;
+-      struct ieee80211_ht_info ht_info;
++      struct ieee80211_sta_ht_cap ht_cap;
+ };
+ /**
+--- everything.orig/net/mac80211/main.c        2008-10-08 20:45:06.000000000 +0200
++++ everything/net/mac80211/main.c     2008-10-09 02:16:29.000000000 +0200
+@@ -232,100 +232,6 @@ int ieee80211_hw_config(struct ieee80211
+       return ret;
+ }
+-/**
+- * ieee80211_handle_ht should be used only after legacy configuration
+- * has been determined namely band, as ht configuration depends upon
+- * the hardware's HT abilities for a _specific_ band.
+- */
+-u32 ieee80211_handle_ht(struct ieee80211_local *local, int enable_ht,
+-                         struct ieee80211_ht_info *req_ht_cap,
+-                         struct ieee80211_ht_bss_info *req_bss_cap)
+-{
+-      struct ieee80211_conf *conf = &local->hw.conf;
+-      struct ieee80211_supported_band *sband;
+-      struct ieee80211_ht_info ht_conf;
+-      struct ieee80211_ht_bss_info ht_bss_conf;
+-      u32 changed = 0;
+-      int i;
+-      u8 max_tx_streams = IEEE80211_HT_CAP_MAX_STREAMS;
+-      u8 tx_mcs_set_cap;
+-
+-      sband = local->hw.wiphy->bands[conf->channel->band];
+-
+-      memset(&ht_conf, 0, sizeof(struct ieee80211_ht_info));
+-      memset(&ht_bss_conf, 0, sizeof(struct ieee80211_ht_bss_info));
+-
+-      /* HT is not supported */
+-      if (!sband->ht_info.ht_supported) {
+-              conf->flags &= ~IEEE80211_CONF_SUPPORT_HT_MODE;
+-              goto out;
+-      }
+-
+-      /* disable HT */
+-      if (!enable_ht) {
+-              if (conf->flags & IEEE80211_CONF_SUPPORT_HT_MODE)
+-                      changed |= BSS_CHANGED_HT;
+-              conf->flags &= ~IEEE80211_CONF_SUPPORT_HT_MODE;
+-              conf->ht_conf.ht_supported = 0;
+-              goto out;
+-      }
+-
+-
+-      if (!(conf->flags & IEEE80211_CONF_SUPPORT_HT_MODE))
+-              changed |= BSS_CHANGED_HT;
+-
+-      conf->flags |= IEEE80211_CONF_SUPPORT_HT_MODE;
+-      ht_conf.ht_supported = 1;
+-
+-      ht_conf.cap = req_ht_cap->cap & sband->ht_info.cap;
+-      ht_conf.cap &= ~(IEEE80211_HT_CAP_SM_PS);
+-      ht_conf.cap |= sband->ht_info.cap & IEEE80211_HT_CAP_SM_PS;
+-      ht_bss_conf.primary_channel = req_bss_cap->primary_channel;
+-      ht_bss_conf.bss_cap = req_bss_cap->bss_cap;
+-      ht_bss_conf.bss_op_mode = req_bss_cap->bss_op_mode;
+-
+-      ht_conf.ampdu_factor = req_ht_cap->ampdu_factor;
+-      ht_conf.ampdu_density = req_ht_cap->ampdu_density;
+-
+-      /* Bits 96-100 */
+-      tx_mcs_set_cap = sband->ht_info.supp_mcs_set[12];
+-
+-      /* configure suppoerted Tx MCS according to requested MCS
+-       * (based in most cases on Rx capabilities of peer) and self
+-       * Tx MCS capabilities (as defined by low level driver HW
+-       * Tx capabilities) */
+-      if (!(tx_mcs_set_cap & IEEE80211_HT_CAP_MCS_TX_DEFINED))
+-              goto check_changed;
+-
+-      /* Counting from 0 therfore + 1 */
+-      if (tx_mcs_set_cap & IEEE80211_HT_CAP_MCS_TX_RX_DIFF)
+-              max_tx_streams = ((tx_mcs_set_cap &
+-                              IEEE80211_HT_CAP_MCS_TX_STREAMS) >> 2) + 1;
+-
+-      for (i = 0; i < max_tx_streams; i++)
+-              ht_conf.supp_mcs_set[i] =
+-                      sband->ht_info.supp_mcs_set[i] &
+-                                      req_ht_cap->supp_mcs_set[i];
+-
+-      if (tx_mcs_set_cap & IEEE80211_HT_CAP_MCS_TX_UEQM)
+-              for (i = IEEE80211_SUPP_MCS_SET_UEQM;
+-                   i < IEEE80211_SUPP_MCS_SET_LEN; i++)
+-                      ht_conf.supp_mcs_set[i] =
+-                              sband->ht_info.supp_mcs_set[i] &
+-                                      req_ht_cap->supp_mcs_set[i];
+-
+-check_changed:
+-      /* if bss configuration changed store the new one */
+-      if (memcmp(&conf->ht_conf, &ht_conf, sizeof(ht_conf)) ||
+-          memcmp(&conf->ht_bss_conf, &ht_bss_conf, sizeof(ht_bss_conf))) {
+-              changed |= BSS_CHANGED_HT;
+-              memcpy(&conf->ht_conf, &ht_conf, sizeof(ht_conf));
+-              memcpy(&conf->ht_bss_conf, &ht_bss_conf, sizeof(ht_bss_conf));
+-      }
+-out:
+-      return changed;
+-}
+-
+ void ieee80211_bss_info_change_notify(struct ieee80211_sub_if_data *sdata,
+                                     u32 changed)
+ {
+--- everything.orig/include/net/mac80211.h     2008-10-08 20:45:06.000000000 +0200
++++ everything/include/net/mac80211.h  2008-10-09 02:16:30.000000000 +0200
+@@ -191,7 +191,7 @@ enum ieee80211_bss_change {
+  * @beacon_int: beacon interval
+  * @assoc_capability: capabilities taken from assoc resp
+  * @assoc_ht: association in HT mode
+- * @ht_conf: ht capabilities
++ * @ht_cap: ht capabilities
+  * @ht_bss_conf: ht extended capabilities
+  * @basic_rates: bitmap of basic rates, each bit stands for an
+  *    index into the rate table configured by the driver in
+@@ -212,7 +212,7 @@ struct ieee80211_bss_conf {
+       u64 basic_rates;
+       /* ht related data */
+       bool assoc_ht;
+-      struct ieee80211_ht_info *ht_conf;
++      struct ieee80211_sta_ht_cap *ht_cap;
+       struct ieee80211_ht_bss_info *ht_bss_conf;
+ };
+@@ -477,7 +477,7 @@ static inline int __deprecated __IEEE802
+  * @antenna_sel_tx: transmit antenna selection, 0: default/diversity,
+  *    1/2: antenna 0/1
+  * @antenna_sel_rx: receive antenna selection, like @antenna_sel_tx
+- * @ht_conf: describes current self configuration of 802.11n HT capabilies
++ * @ht_cap: describes current self configuration of 802.11n HT capabilities
+  * @ht_bss_conf: describes current BSS configuration of 802.11n HT parameters
+  * @channel: the channel to tune to
+  */
+@@ -493,7 +493,7 @@ struct ieee80211_conf {
+       struct ieee80211_channel *channel;
+-      struct ieee80211_ht_info ht_conf;
++      struct ieee80211_sta_ht_cap ht_cap;
+       struct ieee80211_ht_bss_info ht_bss_conf;
+ };
+@@ -686,7 +686,7 @@ enum set_key_cmd {
+  * @addr: MAC address
+  * @aid: AID we assigned to the station if we're an AP
+  * @supp_rates: Bitmap of supported rates (per band)
+- * @ht_info: HT capabilities of this STA
++ * @ht_cap: HT capabilities of this STA
+  * @drv_priv: data area for driver use, will always be aligned to
+  *    sizeof(void *), size is determined in hw information.
+  */
+@@ -694,7 +694,7 @@ struct ieee80211_sta {
+       u64 supp_rates[IEEE80211_NUM_BANDS];
+       u8 addr[ETH_ALEN];
+       u16 aid;
+-      struct ieee80211_ht_info ht_info;
++      struct ieee80211_sta_ht_cap ht_cap;
+       /* must be last */
+       u8 drv_priv[0] __attribute__((__aligned__(sizeof(void *))));
+--- everything.orig/net/mac80211/ieee80211_i.h 2008-10-08 20:45:06.000000000 +0200
++++ everything/net/mac80211/ieee80211_i.h      2008-10-09 02:16:30.000000000 +0200
+@@ -817,7 +817,7 @@ struct ieee802_11_elems {
+       u8 *wmm_info;
+       u8 *wmm_param;
+       struct ieee80211_ht_cap *ht_cap_elem;
+-      struct ieee80211_ht_addt_info *ht_info_elem;
++      struct ieee80211_ht_info *ht_info_elem;
+       u8 *mesh_config;
+       u8 *mesh_id;
+       u8 *peer_link;
+@@ -885,9 +885,6 @@ static inline int ieee80211_bssid_match(
+ int ieee80211_hw_config(struct ieee80211_local *local);
+ int ieee80211_if_config(struct ieee80211_sub_if_data *sdata, u32 changed);
+ void ieee80211_tx_set_protected(struct ieee80211_tx_data *tx);
+-u32 ieee80211_handle_ht(struct ieee80211_local *local, int enable_ht,
+-                      struct ieee80211_ht_info *req_ht_cap,
+-                      struct ieee80211_ht_bss_info *req_bss_cap);
+ void ieee80211_bss_info_change_notify(struct ieee80211_sub_if_data *sdata,
+                                     u32 changed);
+ void ieee80211_configure_filter(struct ieee80211_local *local);
+@@ -968,11 +965,14 @@ int ieee80211_monitor_start_xmit(struct 
+ int ieee80211_subif_start_xmit(struct sk_buff *skb, struct net_device *dev);
+ /* HT */
+-int ieee80211_ht_cap_ie_to_ht_info(struct ieee80211_ht_cap *ht_cap_ie,
+-                                 struct ieee80211_ht_info *ht_info);
+-int ieee80211_ht_addt_info_ie_to_ht_bss_info(
+-                      struct ieee80211_ht_addt_info *ht_add_info_ie,
++void ieee80211_ht_cap_ie_to_sta_ht_cap(struct ieee80211_ht_cap *ht_cap_ie,
++                                     struct ieee80211_sta_ht_cap *ht_cap);
++void ieee80211_ht_info_ie_to_ht_bss_info(
++                      struct ieee80211_ht_info *ht_add_info_ie,
+                       struct ieee80211_ht_bss_info *bss_info);
++u32 ieee80211_handle_ht(struct ieee80211_local *local,
++                      struct ieee80211_sta_ht_cap *req_ht_cap,
++                      struct ieee80211_ht_bss_info *req_bss_cap);
+ void ieee80211_send_bar(struct ieee80211_sub_if_data *sdata, u8 *ra, u16 tid, u16 ssn);
+ void ieee80211_sta_stop_rx_ba_session(struct ieee80211_sub_if_data *sdata, u8 *da,
+--- everything.orig/net/mac80211/wext.c        2008-10-08 20:45:06.000000000 +0200
++++ everything/net/mac80211/wext.c     2008-10-09 02:16:28.000000000 +0200
+@@ -147,7 +147,7 @@ static int ieee80211_ioctl_giwname(struc
+       sband = local->hw.wiphy->bands[IEEE80211_BAND_5GHZ];
+       if (sband) {
+               is_a = 1;
+-              is_ht |= sband->ht_info.ht_supported;
++              is_ht |= sband->ht_cap.ht_supported;
+       }
+       sband = local->hw.wiphy->bands[IEEE80211_BAND_2GHZ];
+@@ -160,7 +160,7 @@ static int ieee80211_ioctl_giwname(struc
+                       if (sband->bitrates[i].bitrate == 60)
+                               is_g = 1;
+               }
+-              is_ht |= sband->ht_info.ht_supported;
++              is_ht |= sband->ht_cap.ht_supported;
+       }
+       strcpy(name, "IEEE 802.11");
+--- everything.orig/net/mac80211/ht.c  2008-10-08 20:44:47.000000000 +0200
++++ everything/net/mac80211/ht.c       2008-10-09 02:16:26.000000000 +0200
+@@ -20,37 +20,33 @@
+ #include "sta_info.h"
+ #include "wme.h"
+-int ieee80211_ht_cap_ie_to_ht_info(struct ieee80211_ht_cap *ht_cap_ie,
+-                                 struct ieee80211_ht_info *ht_info)
++void ieee80211_ht_cap_ie_to_sta_ht_cap(struct ieee80211_ht_cap *ht_cap_ie,
++                                     struct ieee80211_sta_ht_cap *ht_cap)
+ {
+-      if (ht_info == NULL)
+-              return -EINVAL;
++      BUG_ON(!ht_cap);
+-      memset(ht_info, 0, sizeof(*ht_info));
++      memset(ht_cap, 0, sizeof(*ht_cap));
+       if (ht_cap_ie) {
+               u8 ampdu_info = ht_cap_ie->ampdu_params_info;
+-              ht_info->ht_supported = 1;
+-              ht_info->cap = le16_to_cpu(ht_cap_ie->cap_info);
+-              ht_info->ampdu_factor =
+-                      ampdu_info & IEEE80211_HT_CAP_AMPDU_FACTOR;
+-              ht_info->ampdu_density =
+-                      (ampdu_info & IEEE80211_HT_CAP_AMPDU_DENSITY) >> 2;
+-              memcpy(ht_info->supp_mcs_set, ht_cap_ie->supp_mcs_set, 16);
++              ht_cap->ht_supported = true;
++              ht_cap->cap = le16_to_cpu(ht_cap_ie->cap_info);
++              ht_cap->ampdu_factor =
++                      ampdu_info & IEEE80211_HT_AMPDU_PARM_FACTOR;
++              ht_cap->ampdu_density =
++                      (ampdu_info & IEEE80211_HT_AMPDU_PARM_DENSITY) >> 2;
++              memcpy(&ht_cap->mcs, &ht_cap_ie->mcs, sizeof(ht_cap->mcs));
+       } else
+-              ht_info->ht_supported = 0;
+-
+-      return 0;
++              ht_cap->ht_supported = false;
+ }
+-int ieee80211_ht_addt_info_ie_to_ht_bss_info(
+-                      struct ieee80211_ht_addt_info *ht_add_info_ie,
++void ieee80211_ht_info_ie_to_ht_bss_info(
++                      struct ieee80211_ht_info *ht_add_info_ie,
+                       struct ieee80211_ht_bss_info *bss_info)
+ {
+-      if (bss_info == NULL)
+-              return -EINVAL;
++      BUG_ON(!bss_info);
+       memset(bss_info, 0, sizeof(*bss_info));
+@@ -62,8 +58,119 @@ int ieee80211_ht_addt_info_ie_to_ht_bss_
+               bss_info->bss_cap = ht_add_info_ie->ht_param;
+               bss_info->bss_op_mode = (u8)(op_mode & 0xff);
+       }
++}
++
++/*
++ * ieee80211_handle_ht should be called only after the operating band
++ * has been determined as ht configuration depends on the hw's
++ * HT abilities for a specific band.
++ */
++u32 ieee80211_handle_ht(struct ieee80211_local *local,
++                      struct ieee80211_sta_ht_cap *req_ht_cap,
++                      struct ieee80211_ht_bss_info *req_bss_cap)
++{
++      struct ieee80211_conf *conf = &local->hw.conf;
++      struct ieee80211_supported_band *sband;
++      struct ieee80211_sta_ht_cap ht_cap;
++      struct ieee80211_ht_bss_info ht_bss_conf;
++      u32 changed = 0;
++      int i;
++      u8 max_tx_streams;
++      u8 tx_mcs_set_cap;
++      bool enable_ht = true;
++
++      sband = local->hw.wiphy->bands[conf->channel->band];
++
++      memset(&ht_cap, 0, sizeof(ht_cap));
++      memset(&ht_bss_conf, 0, sizeof(struct ieee80211_ht_bss_info));
++
++      /* HT is not supported */
++      if (!sband->ht_cap.ht_supported)
++              enable_ht = false;
++
++      /* disable HT */
++      if (!enable_ht) {
++              if (conf->flags & IEEE80211_CONF_SUPPORT_HT_MODE)
++                      changed |= BSS_CHANGED_HT;
++              conf->flags &= ~IEEE80211_CONF_SUPPORT_HT_MODE;
++              conf->ht_cap.ht_supported = false;
++              return changed;
++      }
++
++
++      if (!(conf->flags & IEEE80211_CONF_SUPPORT_HT_MODE))
++              changed |= BSS_CHANGED_HT;
++
++      conf->flags |= IEEE80211_CONF_SUPPORT_HT_MODE;
++      ht_cap.ht_supported = true;
++
++      ht_cap.cap = req_ht_cap->cap & sband->ht_cap.cap;
++      ht_cap.cap &= ~IEEE80211_HT_CAP_SM_PS;
++      ht_cap.cap |= sband->ht_cap.cap & IEEE80211_HT_CAP_SM_PS;
++
++      ht_bss_conf.primary_channel = req_bss_cap->primary_channel;
++      ht_bss_conf.bss_cap = req_bss_cap->bss_cap;
++      ht_bss_conf.bss_op_mode = req_bss_cap->bss_op_mode;
++
++      ht_cap.ampdu_factor = req_ht_cap->ampdu_factor;
++      ht_cap.ampdu_density = req_ht_cap->ampdu_density;
++
++      /* own MCS TX capabilities */
++      tx_mcs_set_cap = sband->ht_cap.mcs.tx_params;
++
++      /*
++       * configure supported Tx MCS according to requested MCS
++       * (based in most cases on Rx capabilities of peer) and self
++       * Tx MCS capabilities (as defined by low level driver HW
++       * Tx capabilities)
++       */
++
++      /* can we TX with MCS rates? */
++      if (!(tx_mcs_set_cap & IEEE80211_HT_MCS_TX_DEFINED))
++              goto check_changed;
++
++      /* Counting from 0, therefore +1 */
++      if (tx_mcs_set_cap & IEEE80211_HT_MCS_TX_RX_DIFF)
++              max_tx_streams =
++                      ((tx_mcs_set_cap & IEEE80211_HT_MCS_TX_MAX_STREAMS_MASK)
++                              >> IEEE80211_HT_MCS_TX_MAX_STREAMS_SHIFT) + 1;
++      else
++              max_tx_streams = IEEE80211_HT_MCS_TX_MAX_STREAMS;
++
++      /*
++       * 802.11n D5.0 20.3.5 / 20.6 says:
++       * - indices 0 to 7 and 32 are single spatial stream
++       * - 8 to 31 are multiple spatial streams using equal modulation
++       *   [8..15 for two streams, 16..23 for three and 24..31 for four]
++       * - remainder are multiple spatial streams using unequal modulation
++       */
++      for (i = 0; i < max_tx_streams; i++)
++              ht_cap.mcs.rx_mask[i] =
++                      sband->ht_cap.mcs.rx_mask[i] &
++                                      req_ht_cap->mcs.rx_mask[i];
++
++      if (tx_mcs_set_cap & IEEE80211_HT_MCS_TX_UNEQUAL_MODULATION)
++              for (i = IEEE80211_HT_MCS_UNEQUAL_MODULATION_START_BYTE;
++                   i < IEEE80211_HT_MCS_MASK_LEN; i++)
++                      ht_cap.mcs.rx_mask[i] =
++                              sband->ht_cap.mcs.rx_mask[i] &
++                                      req_ht_cap->mcs.rx_mask[i];
++
++      /* handle MCS rate 32 too */
++      if (sband->ht_cap.mcs.rx_mask[32/8] &
++          req_ht_cap->mcs.rx_mask[32/8] & 1)
++              ht_cap.mcs.rx_mask[32/8] |= 1;
++
++ check_changed:
++      /* if bss configuration changed store the new one */
++      if (memcmp(&conf->ht_cap, &ht_cap, sizeof(ht_cap)) ||
++          memcmp(&conf->ht_bss_conf, &ht_bss_conf, sizeof(ht_bss_conf))) {
++              changed |= BSS_CHANGED_HT;
++              memcpy(&conf->ht_cap, &ht_cap, sizeof(ht_cap));
++              memcpy(&conf->ht_bss_conf, &ht_bss_conf, sizeof(ht_bss_conf));
++      }
+-      return 0;
++      return changed;
+ }
+ static void ieee80211_send_addba_request(struct ieee80211_sub_if_data *sdata,
+@@ -802,7 +909,7 @@ void ieee80211_process_addba_request(str
+        * check if configuration can support the BA policy
+        * and if buffer size does not exceeds max value */
+       if (((ba_policy != 1)
+-              && (!(conf->ht_conf.cap & IEEE80211_HT_CAP_DELAY_BA)))
++              && (!(conf->ht_cap.cap & IEEE80211_HT_CAP_DELAY_BA)))
+               || (buf_size > IEEE80211_MAX_AMPDU_BUF)) {
+               status = WLAN_STATUS_INVALID_QOS_PARAM;
+ #ifdef CONFIG_MAC80211_HT_DEBUG
+@@ -820,7 +927,7 @@ void ieee80211_process_addba_request(str
+               sband = local->hw.wiphy->bands[conf->channel->band];
+               buf_size = IEEE80211_MIN_AMPDU_BUF;
+-              buf_size = buf_size << sband->ht_info.ampdu_factor;
++              buf_size = buf_size << sband->ht_cap.ampdu_factor;
+       }
+--- everything.orig/net/mac80211/mlme.c        2008-10-08 20:45:06.000000000 +0200
++++ everything/net/mac80211/mlme.c     2008-10-09 02:16:26.000000000 +0200
+@@ -236,7 +236,7 @@ static void ieee80211_send_assoc(struct 
+       struct ieee80211_local *local = sdata->local;
+       struct sk_buff *skb;
+       struct ieee80211_mgmt *mgmt;
+-      u8 *pos, *ies, *ht_add_ie;
++      u8 *pos, *ies, *ht_ie;
+       int i, len, count, rates_len, supp_rates_len;
+       u16 capab;
+       struct ieee80211_bss *bss;
+@@ -393,24 +393,25 @@ static void ieee80211_send_assoc(struct 
+       /* wmm support is a must to HT */
+       if (wmm && (ifsta->flags & IEEE80211_STA_WMM_ENABLED) &&
+-          sband->ht_info.ht_supported &&
+-          (ht_add_ie = ieee80211_bss_get_ie(bss, WLAN_EID_HT_EXTRA_INFO))) {
+-              struct ieee80211_ht_addt_info *ht_add_info =
+-                      (struct ieee80211_ht_addt_info *)ht_add_ie;
+-              u16 cap = sband->ht_info.cap;
++          sband->ht_cap.ht_supported &&
++          (ht_ie = ieee80211_bss_get_ie(bss, WLAN_EID_HT_INFORMATION)) &&
++          ht_ie[1] >= sizeof(struct ieee80211_ht_info)) {
++              struct ieee80211_ht_info *ht_info =
++                      (struct ieee80211_ht_info *)(ht_ie + 2);
++              u16 cap = sband->ht_cap.cap;
+               __le16 tmp;
+               u32 flags = local->hw.conf.channel->flags;
+-              switch (ht_add_info->ht_param & IEEE80211_HT_IE_CHA_SEC_OFFSET) {
+-              case IEEE80211_HT_IE_CHA_SEC_ABOVE:
++              switch (ht_info->ht_param & IEEE80211_HT_PARAM_CHA_SEC_OFFSET) {
++              case IEEE80211_HT_PARAM_CHA_SEC_ABOVE:
+                       if (flags & IEEE80211_CHAN_NO_FAT_ABOVE) {
+-                              cap &= ~IEEE80211_HT_CAP_SUP_WIDTH;
++                              cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40;
+                               cap &= ~IEEE80211_HT_CAP_SGI_40;
+                       }
+                       break;
+-              case IEEE80211_HT_IE_CHA_SEC_BELOW:
++              case IEEE80211_HT_PARAM_CHA_SEC_BELOW:
+                       if (flags & IEEE80211_CHAN_NO_FAT_BELOW) {
+-                              cap &= ~IEEE80211_HT_CAP_SUP_WIDTH;
++                              cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40;
+                               cap &= ~IEEE80211_HT_CAP_SGI_40;
+                       }
+                       break;
+@@ -424,9 +425,9 @@ static void ieee80211_send_assoc(struct 
+               memcpy(pos, &tmp, sizeof(u16));
+               pos += sizeof(u16);
+               /* TODO: needs a define here for << 2 */
+-              *pos++ = sband->ht_info.ampdu_factor |
+-                       (sband->ht_info.ampdu_density << 2);
+-              memcpy(pos, sband->ht_info.supp_mcs_set, 16);
++              *pos++ = sband->ht_cap.ampdu_factor |
++                       (sband->ht_cap.ampdu_density << 2);
++              memcpy(pos, &sband->ht_cap.mcs, sizeof(sband->ht_cap.mcs));
+       }
+       kfree(ifsta->assocreq_ies);
+@@ -732,7 +733,7 @@ static void ieee80211_set_associated(str
+       if (conf->flags & IEEE80211_CONF_SUPPORT_HT_MODE) {
+               changed |= BSS_CHANGED_HT;
+               sdata->bss_conf.assoc_ht = 1;
+-              sdata->bss_conf.ht_conf = &conf->ht_conf;
++              sdata->bss_conf.ht_cap = &conf->ht_cap;
+               sdata->bss_conf.ht_bss_conf = &conf->ht_bss_conf;
+       }
+@@ -856,7 +857,7 @@ static void ieee80211_set_disassoc(struc
+               changed |= BSS_CHANGED_HT;
+       sdata->bss_conf.assoc_ht = 0;
+-      sdata->bss_conf.ht_conf = NULL;
++      sdata->bss_conf.ht_cap = NULL;
+       sdata->bss_conf.ht_bss_conf = NULL;
+       ieee80211_led_assoc(local, 0);
+@@ -1348,11 +1349,11 @@ static void ieee80211_rx_mgmt_assoc_resp
+       if (elems.ht_cap_elem && elems.ht_info_elem && elems.wmm_param &&
+           (ifsta->flags & IEEE80211_STA_WMM_ENABLED)) {
+               struct ieee80211_ht_bss_info bss_info;
+-              ieee80211_ht_cap_ie_to_ht_info(
+-                              elems.ht_cap_elem, &sta->sta.ht_info);
+-              ieee80211_ht_addt_info_ie_to_ht_bss_info(
++              ieee80211_ht_cap_ie_to_sta_ht_cap(
++                              elems.ht_cap_elem, &sta->sta.ht_cap);
++              ieee80211_ht_info_ie_to_ht_bss_info(
+                               elems.ht_info_elem, &bss_info);
+-              ieee80211_handle_ht(local, 1, &sta->sta.ht_info, &bss_info);
++              ieee80211_handle_ht(local, &sta->sta.ht_cap, &bss_info);
+       }
+       rate_control_rate_init(sta);
+@@ -1712,9 +1713,9 @@ static void ieee80211_rx_mgmt_beacon(str
+           elems.wmm_param && conf->flags & IEEE80211_CONF_SUPPORT_HT_MODE) {
+               struct ieee80211_ht_bss_info bss_info;
+-              ieee80211_ht_addt_info_ie_to_ht_bss_info(
++              ieee80211_ht_info_ie_to_ht_bss_info(
+                               elems.ht_info_elem, &bss_info);
+-              changed |= ieee80211_handle_ht(local, 1, &conf->ht_conf,
++              changed |= ieee80211_handle_ht(local, &conf->ht_cap,
+                                              &bss_info);
+       }
+--- everything.orig/net/mac80211/util.c        2008-10-08 20:45:06.000000000 +0200
++++ everything/net/mac80211/util.c     2008-10-09 02:16:28.000000000 +0200
+@@ -532,8 +532,8 @@ void ieee802_11_parse_elems(u8 *start, s
+                       if (elen >= sizeof(struct ieee80211_ht_cap))
+                               elems->ht_cap_elem = (void *)pos;
+                       break;
+-              case WLAN_EID_HT_EXTRA_INFO:
+-                      if (elen >= sizeof(struct ieee80211_ht_addt_info))
++              case WLAN_EID_HT_INFORMATION:
++                      if (elen >= sizeof(struct ieee80211_ht_info))
+                               elems->ht_info_elem = (void *)pos;
+                       break;
+               case WLAN_EID_MESH_ID:
+--- everything.orig/net/mac80211/cfg.c 2008-10-08 20:45:06.000000000 +0200
++++ everything/net/mac80211/cfg.c      2008-10-09 02:16:29.000000000 +0200
+@@ -635,10 +635,9 @@ static void sta_apply_parameters(struct 
+               sta->sta.supp_rates[local->oper_channel->band] = rates;
+       }
+-      if (params->ht_capa) {
+-              ieee80211_ht_cap_ie_to_ht_info(params->ht_capa,
+-                                             &sta->sta.ht_info);
+-      }
++      if (params->ht_capa)
++              ieee80211_ht_cap_ie_to_sta_ht_cap(params->ht_capa,
++                                                &sta->sta.ht_cap);
+       if (ieee80211_vif_is_mesh(&sdata->vif) && params->plink_action) {
+               switch (params->plink_action) {
+--- everything.orig/drivers/net/wireless/iwlwifi/iwl-agn-rs.c  2008-10-08 20:44:47.000000000 +0200
++++ everything/drivers/net/wireless/iwlwifi/iwl-agn-rs.c       2008-10-09 02:16:27.000000000 +0200
+@@ -1136,10 +1136,10 @@ static int rs_switch_to_mimo2(struct iwl
+       s8 is_green = lq_sta->is_green;
+       if (!(conf->flags & IEEE80211_CONF_SUPPORT_HT_MODE) ||
+-          !sta->ht_info.ht_supported)
++          !sta->ht_cap.ht_supported)
+               return -1;
+-      if (((sta->ht_info.cap & IEEE80211_HT_CAP_SM_PS) >> 2)
++      if (((sta->ht_cap.cap & IEEE80211_HT_CAP_SM_PS) >> 2)
+                                               == WLAN_HT_CAP_SM_PS_STATIC)
+               return -1;
+@@ -1204,7 +1204,7 @@ static int rs_switch_to_siso(struct iwl_
+       s32 rate;
+       if (!(conf->flags & IEEE80211_CONF_SUPPORT_HT_MODE) ||
+-          !sta->ht_info.ht_supported)
++          !sta->ht_cap.ht_supported)
+               return -1;
+       IWL_DEBUG_RATE("LQ: try to switch to SISO\n");
+@@ -2244,19 +2244,19 @@ static void rs_rate_init(void *priv_r, s
+        * active_siso_rate mask includes 9 MBits (bit 5), and CCK (bits 0-3),
+        * supp_rates[] does not; shift to convert format, force 9 MBits off.
+        */
+-      lq_sta->active_siso_rate = conf->ht_conf.supp_mcs_set[0] << 1;
+-      lq_sta->active_siso_rate |= conf->ht_conf.supp_mcs_set[0] & 0x1;
++      lq_sta->active_siso_rate = conf->ht_cap.mcs.rx_mask[0] << 1;
++      lq_sta->active_siso_rate |= conf->ht_cap.mcs.rx_mask[0] & 0x1;
+       lq_sta->active_siso_rate &= ~((u16)0x2);
+       lq_sta->active_siso_rate <<= IWL_FIRST_OFDM_RATE;
+       /* Same here */
+-      lq_sta->active_mimo2_rate = conf->ht_conf.supp_mcs_set[1] << 1;
+-      lq_sta->active_mimo2_rate |= conf->ht_conf.supp_mcs_set[1] & 0x1;
++      lq_sta->active_mimo2_rate = conf->ht_cap.mcs.rx_mask[1] << 1;
++      lq_sta->active_mimo2_rate |= conf->ht_cap.mcs.rx_mask[1] & 0x1;
+       lq_sta->active_mimo2_rate &= ~((u16)0x2);
+       lq_sta->active_mimo2_rate <<= IWL_FIRST_OFDM_RATE;
+-      lq_sta->active_mimo3_rate = conf->ht_conf.supp_mcs_set[2] << 1;
+-      lq_sta->active_mimo3_rate |= conf->ht_conf.supp_mcs_set[2] & 0x1;
++      lq_sta->active_mimo3_rate = conf->ht_cap.mcs.rx_mask[2] << 1;
++      lq_sta->active_mimo3_rate |= conf->ht_cap.mcs.rx_mask[2] & 0x1;
+       lq_sta->active_mimo3_rate &= ~((u16)0x2);
+       lq_sta->active_mimo3_rate <<= IWL_FIRST_OFDM_RATE;
+--- everything.orig/drivers/net/wireless/iwlwifi/iwl-agn.c     2008-10-08 20:44:48.000000000 +0200
++++ everything/drivers/net/wireless/iwlwifi/iwl-agn.c  2008-10-09 02:16:29.000000000 +0200
+@@ -553,7 +553,7 @@ static int iwl4965_send_beacon_cmd(struc
+ static void iwl4965_ht_conf(struct iwl_priv *priv,
+                           struct ieee80211_bss_conf *bss_conf)
+ {
+-      struct ieee80211_ht_info *ht_conf = bss_conf->ht_conf;
++      struct ieee80211_sta_ht_cap *ht_conf = bss_conf->ht_cap;
+       struct ieee80211_ht_bss_info *ht_bss_conf = bss_conf->ht_bss_conf;
+       struct iwl_ht_info *iwl_conf = &priv->current_ht_config;
+@@ -574,27 +574,27 @@ static void iwl4965_ht_conf(struct iwl_p
+               !!(ht_conf->cap & IEEE80211_HT_CAP_MAX_AMSDU);
+       iwl_conf->supported_chan_width =
+-              !!(ht_conf->cap & IEEE80211_HT_CAP_SUP_WIDTH);
++              !!(ht_conf->cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40);
+       iwl_conf->extension_chan_offset =
+-              ht_bss_conf->bss_cap & IEEE80211_HT_IE_CHA_SEC_OFFSET;
++              ht_bss_conf->bss_cap & IEEE80211_HT_PARAM_CHA_SEC_OFFSET;
+       /* If no above or below channel supplied disable FAT channel */
+-      if (iwl_conf->extension_chan_offset != IEEE80211_HT_IE_CHA_SEC_ABOVE &&
+-          iwl_conf->extension_chan_offset != IEEE80211_HT_IE_CHA_SEC_BELOW) {
+-              iwl_conf->extension_chan_offset = IEEE80211_HT_IE_CHA_SEC_NONE;
++      if (iwl_conf->extension_chan_offset != IEEE80211_HT_PARAM_CHA_SEC_ABOVE &&
++          iwl_conf->extension_chan_offset != IEEE80211_HT_PARAM_CHA_SEC_BELOW) {
++              iwl_conf->extension_chan_offset = IEEE80211_HT_PARAM_CHA_SEC_NONE;
+               iwl_conf->supported_chan_width = 0;
+       }
+       iwl_conf->sm_ps = (u8)((ht_conf->cap & IEEE80211_HT_CAP_SM_PS) >> 2);
+-      memcpy(iwl_conf->supp_mcs_set, ht_conf->supp_mcs_set, 16);
++      memcpy(&iwl_conf->mcs, &ht_conf->mcs, 16);
+       iwl_conf->control_channel = ht_bss_conf->primary_channel;
+       iwl_conf->tx_chan_width =
+-              !!(ht_bss_conf->bss_cap & IEEE80211_HT_IE_CHA_WIDTH);
++              !!(ht_bss_conf->bss_cap & IEEE80211_HT_PARAM_CHAN_WIDTH_ANY);
+       iwl_conf->ht_protection =
+-              ht_bss_conf->bss_op_mode & IEEE80211_HT_IE_HT_PROTECTION;
++              ht_bss_conf->bss_op_mode & IEEE80211_HT_OP_MODE_PROTECTION;
+       iwl_conf->non_GF_STA_present =
+-              !!(ht_bss_conf->bss_op_mode & IEEE80211_HT_IE_NON_GF_STA_PRSNT);
++              !!(ht_bss_conf->bss_op_mode & IEEE80211_HT_OP_MODE_NON_GF_STA_PRSNT);
+       IWL_DEBUG_MAC80211("control channel %d\n", iwl_conf->control_channel);
+       IWL_DEBUG_MAC80211("leave\n");
+--- everything.orig/drivers/net/wireless/iwlwifi/iwl-core.c    2008-10-08 20:44:47.000000000 +0200
++++ everything/drivers/net/wireless/iwlwifi/iwl-core.c 2008-10-09 02:16:26.000000000 +0200
+@@ -382,10 +382,10 @@ void iwl_reset_qos(struct iwl_priv *priv
+ }
+ EXPORT_SYMBOL(iwl_reset_qos);
+-#define MAX_BIT_RATE_40_MHZ 0x96 /* 150 Mbps */
+-#define MAX_BIT_RATE_20_MHZ 0x48 /* 72 Mbps */
++#define MAX_BIT_RATE_40_MHZ 150 /* Mbps */
++#define MAX_BIT_RATE_20_MHZ 72 /* Mbps */
+ static void iwlcore_init_ht_hw_capab(const struct iwl_priv *priv,
+-                            struct ieee80211_ht_info *ht_info,
++                            struct ieee80211_sta_ht_cap *ht_info,
+                             enum ieee80211_band band)
+ {
+       u16 max_bit_rate = 0;
+@@ -393,45 +393,46 @@ static void iwlcore_init_ht_hw_capab(con
+       u8 tx_chains_num = priv->hw_params.tx_chains_num;
+       ht_info->cap = 0;
+-      memset(ht_info->supp_mcs_set, 0, 16);
++      memset(&ht_info->mcs, 0, sizeof(ht_info->mcs));
+-      ht_info->ht_supported = 1;
++      ht_info->ht_supported = true;
+-      ht_info->cap |= (u16)IEEE80211_HT_CAP_GRN_FLD;
+-      ht_info->cap |= (u16)IEEE80211_HT_CAP_SGI_20;
+-      ht_info->cap |= (u16)(IEEE80211_HT_CAP_SM_PS &
++      ht_info->cap |= IEEE80211_HT_CAP_GRN_FLD;
++      ht_info->cap |= IEEE80211_HT_CAP_SGI_20;
++      ht_info->cap |= (IEEE80211_HT_CAP_SM_PS &
+                            (WLAN_HT_CAP_SM_PS_DISABLED << 2));
+       max_bit_rate = MAX_BIT_RATE_20_MHZ;
+       if (priv->hw_params.fat_channel & BIT(band)) {
+-              ht_info->cap |= (u16)IEEE80211_HT_CAP_SUP_WIDTH;
+-              ht_info->cap |= (u16)IEEE80211_HT_CAP_SGI_40;
+-              ht_info->supp_mcs_set[4] = 0x01;
++              ht_info->cap |= IEEE80211_HT_CAP_SUP_WIDTH_20_40;
++              ht_info->cap |= IEEE80211_HT_CAP_SGI_40;
++              ht_info->mcs.rx_mask[4] = 0x01;
+               max_bit_rate = MAX_BIT_RATE_40_MHZ;
+       }
+       if (priv->cfg->mod_params->amsdu_size_8K)
+-              ht_info->cap |= (u16)IEEE80211_HT_CAP_MAX_AMSDU;
++              ht_info->cap |= IEEE80211_HT_CAP_MAX_AMSDU;
+       ht_info->ampdu_factor = CFG_HT_RX_AMPDU_FACTOR_DEF;
+       ht_info->ampdu_density = CFG_HT_MPDU_DENSITY_DEF;
+-      ht_info->supp_mcs_set[0] = 0xFF;
++      ht_info->mcs.rx_mask[0] = 0xFF;
+       if (rx_chains_num >= 2)
+-              ht_info->supp_mcs_set[1] = 0xFF;
++              ht_info->mcs.rx_mask[1] = 0xFF;
+       if (rx_chains_num >= 3)
+-              ht_info->supp_mcs_set[2] = 0xFF;
++              ht_info->mcs.rx_mask[2] = 0xFF;
+       /* Highest supported Rx data rate */
+       max_bit_rate *= rx_chains_num;
+-      ht_info->supp_mcs_set[10] = (u8)(max_bit_rate & 0x00FF);
+-      ht_info->supp_mcs_set[11] = (u8)((max_bit_rate & 0xFF00) >> 8);
++      WARN_ON(max_bit_rate & ~IEEE80211_HT_MCS_RX_HIGHEST_MASK);
++      ht_info->mcs.rx_highest = cpu_to_le16(max_bit_rate);
+       /* Tx MCS capabilities */
+-      ht_info->supp_mcs_set[12] = IEEE80211_HT_CAP_MCS_TX_DEFINED;
++      ht_info->mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED;
+       if (tx_chains_num != rx_chains_num) {
+-              ht_info->supp_mcs_set[12] |= IEEE80211_HT_CAP_MCS_TX_RX_DIFF;
+-              ht_info->supp_mcs_set[12] |= ((tx_chains_num - 1) << 2);
++              ht_info->mcs.tx_params |= IEEE80211_HT_MCS_TX_RX_DIFF;
++              ht_info->mcs.tx_params |= ((tx_chains_num - 1) <<
++                              IEEE80211_HT_MCS_TX_MAX_STREAMS_SHIFT);
+       }
+ }
+@@ -495,7 +496,7 @@ static int iwlcore_init_geos(struct iwl_
+       sband->n_bitrates = IWL_RATE_COUNT - IWL_FIRST_OFDM_RATE;
+       if (priv->cfg->sku & IWL_SKU_N)
+-              iwlcore_init_ht_hw_capab(priv, &sband->ht_info,
++              iwlcore_init_ht_hw_capab(priv, &sband->ht_cap,
+                                        IEEE80211_BAND_5GHZ);
+       sband = &priv->bands[IEEE80211_BAND_2GHZ];
+@@ -505,7 +506,7 @@ static int iwlcore_init_geos(struct iwl_
+       sband->n_bitrates = IWL_RATE_COUNT;
+       if (priv->cfg->sku & IWL_SKU_N)
+-              iwlcore_init_ht_hw_capab(priv, &sband->ht_info,
++              iwlcore_init_ht_hw_capab(priv, &sband->ht_cap,
+                                        IEEE80211_BAND_2GHZ);
+       priv->ieee_channels = channels;
+@@ -595,8 +596,8 @@ static void iwlcore_free_geos(struct iwl
+ static bool is_single_rx_stream(struct iwl_priv *priv)
+ {
+       return !priv->current_ht_config.is_ht ||
+-             ((priv->current_ht_config.supp_mcs_set[1] == 0) &&
+-              (priv->current_ht_config.supp_mcs_set[2] == 0));
++             ((priv->current_ht_config.mcs.rx_mask[1] == 0) &&
++              (priv->current_ht_config.mcs.rx_mask[2] == 0));
+ }
+ static u8 iwl_is_channel_extension(struct iwl_priv *priv,
+@@ -609,10 +610,10 @@ static u8 iwl_is_channel_extension(struc
+       if (!is_channel_valid(ch_info))
+               return 0;
+-      if (extension_chan_offset == IEEE80211_HT_IE_CHA_SEC_ABOVE)
++      if (extension_chan_offset == IEEE80211_HT_PARAM_CHA_SEC_ABOVE)
+               return !(ch_info->fat_extension_channel &
+                                       IEEE80211_CHAN_NO_FAT_ABOVE);
+-      else if (extension_chan_offset == IEEE80211_HT_IE_CHA_SEC_BELOW)
++      else if (extension_chan_offset == IEEE80211_HT_PARAM_CHA_SEC_BELOW)
+               return !(ch_info->fat_extension_channel &
+                                       IEEE80211_CHAN_NO_FAT_BELOW);
+@@ -620,18 +621,18 @@ static u8 iwl_is_channel_extension(struc
+ }
+ u8 iwl_is_fat_tx_allowed(struct iwl_priv *priv,
+-                           struct ieee80211_ht_info *sta_ht_inf)
++                       struct ieee80211_sta_ht_cap *sta_ht_inf)
+ {
+       struct iwl_ht_info *iwl_ht_conf = &priv->current_ht_config;
+       if ((!iwl_ht_conf->is_ht) ||
+          (iwl_ht_conf->supported_chan_width != IWL_CHANNEL_WIDTH_40MHZ) ||
+-         (iwl_ht_conf->extension_chan_offset == IEEE80211_HT_IE_CHA_SEC_NONE))
++         (iwl_ht_conf->extension_chan_offset == IEEE80211_HT_PARAM_CHA_SEC_NONE))
+               return 0;
+       if (sta_ht_inf) {
+               if ((!sta_ht_inf->ht_supported) ||
+-                 (!(sta_ht_inf->cap & IEEE80211_HT_CAP_SUP_WIDTH)))
++                 (!(sta_ht_inf->cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40)))
+                       return 0;
+       }
+@@ -671,13 +672,13 @@ void iwl_set_rxon_ht(struct iwl_priv *pr
+       /* Note: control channel is opposite of extension channel */
+       switch (ht_info->extension_chan_offset) {
+-      case IEEE80211_HT_IE_CHA_SEC_ABOVE:
++      case IEEE80211_HT_PARAM_CHA_SEC_ABOVE:
+               rxon->flags &= ~(RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK);
+               break;
+-      case IEEE80211_HT_IE_CHA_SEC_BELOW:
++      case IEEE80211_HT_PARAM_CHA_SEC_BELOW:
+               rxon->flags |= RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK;
+               break;
+-      case IEEE80211_HT_IE_CHA_SEC_NONE:
++      case IEEE80211_HT_PARAM_CHA_SEC_NONE:
+       default:
+               rxon->flags &= ~RXON_FLG_CHANNEL_MODE_MIXED_MSK;
+               break;
+@@ -693,9 +694,9 @@ void iwl_set_rxon_ht(struct iwl_priv *pr
+                       "rxon flags 0x%X operation mode :0x%X "
+                       "extension channel offset 0x%x "
+                       "control chan %d\n",
+-                      ht_info->supp_mcs_set[0],
+-                      ht_info->supp_mcs_set[1],
+-                      ht_info->supp_mcs_set[2],
++                      ht_info->mcs.rx_mask[0],
++                      ht_info->mcs.rx_mask[1],
++                      ht_info->mcs.rx_mask[2],
+                       le32_to_cpu(rxon->flags), ht_info->ht_protection,
+                       ht_info->extension_chan_offset,
+                       ht_info->control_channel);
+--- everything.orig/drivers/net/wireless/iwlwifi/iwl-core.h    2008-10-08 20:44:47.000000000 +0200
++++ everything/drivers/net/wireless/iwlwifi/iwl-core.h 2008-10-08 20:45:06.000000000 +0200
+@@ -190,7 +190,7 @@ void iwl_set_rxon_chain(struct iwl_priv 
+ int iwl_set_rxon_channel(struct iwl_priv *priv, struct ieee80211_channel *ch);
+ void iwl_set_rxon_ht(struct iwl_priv *priv, struct iwl_ht_info *ht_info);
+ u8 iwl_is_fat_tx_allowed(struct iwl_priv *priv,
+-                       struct ieee80211_ht_info *sta_ht_inf);
++                       struct ieee80211_sta_ht_cap *sta_ht_inf);
+ int iwl_hw_nic_init(struct iwl_priv *priv);
+ int iwl_setup_mac(struct iwl_priv *priv);
+ int iwl_set_hw_params(struct iwl_priv *priv);
+--- everything.orig/drivers/net/wireless/iwlwifi/iwl-dev.h     2008-10-08 20:44:47.000000000 +0200
++++ everything/drivers/net/wireless/iwlwifi/iwl-dev.h  2008-10-09 02:16:27.000000000 +0200
+@@ -412,7 +412,7 @@ struct iwl_ht_info {
+       u8 max_amsdu_size;
+       u8 ampdu_factor;
+       u8 mpdu_density;
+-      u8 supp_mcs_set[16];
++      struct ieee80211_mcs_info mcs;
+       /* BSS related data */
+       u8 control_channel;
+       u8 extension_chan_offset;
+@@ -584,7 +584,7 @@ struct iwl_addsta_cmd;
+ extern int iwl_send_add_sta(struct iwl_priv *priv,
+                           struct iwl_addsta_cmd *sta, u8 flags);
+ extern u8 iwl_add_station_flags(struct iwl_priv *priv, const u8 *addr,
+-                      int is_ap, u8 flags, struct ieee80211_ht_info *ht_info);
++                      int is_ap, u8 flags, struct ieee80211_sta_ht_cap *ht_info);
+ extern void iwl4965_update_chain_flags(struct iwl_priv *priv);
+ extern int iwl4965_set_pwr_src(struct iwl_priv *priv, enum iwl_pwr_src src);
+ extern const u8 iwl_bcast_addr[ETH_ALEN];
+--- everything.orig/drivers/net/wireless/iwlwifi/iwl-sta.c     2008-10-08 20:44:47.000000000 +0200
++++ everything/drivers/net/wireless/iwlwifi/iwl-sta.c  2008-10-09 02:16:29.000000000 +0200
+@@ -183,7 +183,7 @@ int iwl_send_add_sta(struct iwl_priv *pr
+ EXPORT_SYMBOL(iwl_send_add_sta);
+ static void iwl_set_ht_add_station(struct iwl_priv *priv, u8 index,
+-                                 struct ieee80211_ht_info *sta_ht_inf)
++                                 struct ieee80211_sta_ht_cap *sta_ht_inf)
+ {
+       __le32 sta_flags;
+       u8 mimo_ps_mode;
+@@ -231,7 +231,7 @@ static void iwl_set_ht_add_station(struc
+  * iwl_add_station_flags - Add station to tables in driver and device
+  */
+ u8 iwl_add_station_flags(struct iwl_priv *priv, const u8 *addr, int is_ap,
+-                       u8 flags, struct ieee80211_ht_info *ht_info)
++                       u8 flags, struct ieee80211_sta_ht_cap *ht_info)
+ {
+       int i;
+       int sta_id = IWL_INVALID_STATION;
+@@ -900,7 +900,7 @@ int iwl_rxon_add_station(struct iwl_priv
+       /* Add station to device's station table */
+       struct ieee80211_conf *conf = &priv->hw->conf;
+-      struct ieee80211_ht_info *cur_ht_config = &conf->ht_conf;
++      struct ieee80211_sta_ht_cap *cur_ht_config = &conf->ht_cap;
+       if ((is_ap) &&
+           (conf->flags & IEEE80211_CONF_SUPPORT_HT_MODE) &&
+--- everything.orig/drivers/net/wireless/iwlwifi/iwl-scan.c    2008-10-08 20:44:47.000000000 +0200
++++ everything/drivers/net/wireless/iwlwifi/iwl-scan.c 2008-10-08 20:45:06.000000000 +0200
+@@ -550,7 +550,7 @@ static void iwl_ht_cap_to_ie(const struc
+ {
+       struct ieee80211_ht_cap *ht_cap;
+-      if (!sband || !sband->ht_info.ht_supported)
++      if (!sband || !sband->ht_cap.ht_supported)
+               return;
+       if (*left < sizeof(struct ieee80211_ht_cap))
+@@ -559,12 +559,12 @@ static void iwl_ht_cap_to_ie(const struc
+       *pos++ = sizeof(struct ieee80211_ht_cap);
+       ht_cap = (struct ieee80211_ht_cap *) pos;
+-      ht_cap->cap_info = cpu_to_le16(sband->ht_info.cap);
+-      memcpy(ht_cap->supp_mcs_set, sband->ht_info.supp_mcs_set, 16);
++      ht_cap->cap_info = cpu_to_le16(sband->ht_cap.cap);
++      memcpy(&ht_cap->mcs, &sband->ht_cap.mcs, 16);
+       ht_cap->ampdu_params_info =
+-              (sband->ht_info.ampdu_factor & IEEE80211_HT_CAP_AMPDU_FACTOR) |
+-              ((sband->ht_info.ampdu_density << 2) &
+-                      IEEE80211_HT_CAP_AMPDU_DENSITY);
++              (sband->ht_cap.ampdu_factor & IEEE80211_HT_AMPDU_PARM_FACTOR) |
++              ((sband->ht_cap.ampdu_density << 2) &
++                      IEEE80211_HT_AMPDU_PARM_DENSITY);
+       *left -= sizeof(struct ieee80211_ht_cap);
+ }
+--- everything.orig/drivers/net/wireless/ath9k/main.c  2008-10-08 20:44:48.000000000 +0200
++++ everything/drivers/net/wireless/ath9k/main.c       2008-10-09 02:16:30.000000000 +0200
+@@ -61,24 +61,24 @@ static u32 ath_get_extchanmode(struct at
+       switch (chan->band) {
+       case IEEE80211_BAND_2GHZ:
+-              if ((ext_chan_offset == IEEE80211_HT_IE_CHA_SEC_NONE) &&
++              if ((ext_chan_offset == IEEE80211_HT_PARAM_CHA_SEC_NONE) &&
+                   (tx_chan_width == ATH9K_HT_MACMODE_20))
+                       chanmode = CHANNEL_G_HT20;
+-              if ((ext_chan_offset == IEEE80211_HT_IE_CHA_SEC_ABOVE) &&
++              if ((ext_chan_offset == IEEE80211_HT_PARAM_CHA_SEC_ABOVE) &&
+                   (tx_chan_width == ATH9K_HT_MACMODE_2040))
+                       chanmode = CHANNEL_G_HT40PLUS;
+-              if ((ext_chan_offset == IEEE80211_HT_IE_CHA_SEC_BELOW) &&
++              if ((ext_chan_offset == IEEE80211_HT_PARAM_CHA_SEC_BELOW) &&
+                   (tx_chan_width == ATH9K_HT_MACMODE_2040))
+                       chanmode = CHANNEL_G_HT40MINUS;
+               break;
+       case IEEE80211_BAND_5GHZ:
+-              if ((ext_chan_offset == IEEE80211_HT_IE_CHA_SEC_NONE) &&
++              if ((ext_chan_offset == IEEE80211_HT_PARAM_CHA_SEC_NONE) &&
+                   (tx_chan_width == ATH9K_HT_MACMODE_20))
+                       chanmode = CHANNEL_A_HT20;
+-              if ((ext_chan_offset == IEEE80211_HT_IE_CHA_SEC_ABOVE) &&
++              if ((ext_chan_offset == IEEE80211_HT_PARAM_CHA_SEC_ABOVE) &&
+                   (tx_chan_width == ATH9K_HT_MACMODE_2040))
+                       chanmode = CHANNEL_A_HT40PLUS;
+-              if ((ext_chan_offset == IEEE80211_HT_IE_CHA_SEC_BELOW) &&
++              if ((ext_chan_offset == IEEE80211_HT_PARAM_CHA_SEC_BELOW) &&
+                   (tx_chan_width == ATH9K_HT_MACMODE_2040))
+                       chanmode = CHANNEL_A_HT40MINUS;
+               break;
+@@ -215,24 +215,24 @@ static void ath_key_delete(struct ath_so
+       ath_key_reset(sc, key->keyidx, freeslot);
+ }
+-static void setup_ht_cap(struct ieee80211_ht_info *ht_info)
++static void setup_ht_cap(struct ieee80211_sta_ht_cap *ht_info)
+ {
+ #define       ATH9K_HT_CAP_MAXRXAMPDU_65536 0x3       /* 2 ^ 16 */
+ #define       ATH9K_HT_CAP_MPDUDENSITY_8 0x6          /* 8 usec */
+-      ht_info->ht_supported = 1;
+-      ht_info->cap = (u16)IEEE80211_HT_CAP_SUP_WIDTH
+-                      |(u16)IEEE80211_HT_CAP_SM_PS
+-                      |(u16)IEEE80211_HT_CAP_SGI_40
+-                      |(u16)IEEE80211_HT_CAP_DSSSCCK40;
++      ht_info->ht_supported = true;
++      ht_info->cap = IEEE80211_HT_CAP_SUP_WIDTH_20_40 |
++                     IEEE80211_HT_CAP_SM_PS |
++                     IEEE80211_HT_CAP_SGI_40 |
++                     IEEE80211_HT_CAP_DSSSCCK40;
+       ht_info->ampdu_factor = ATH9K_HT_CAP_MAXRXAMPDU_65536;
+       ht_info->ampdu_density = ATH9K_HT_CAP_MPDUDENSITY_8;
+-      /* setup supported mcs set */
+-      memset(ht_info->supp_mcs_set, 0, 16);
+-      ht_info->supp_mcs_set[0] = 0xff;
+-      ht_info->supp_mcs_set[1] = 0xff;
+-      ht_info->supp_mcs_set[12] = IEEE80211_HT_CAP_MCS_TX_DEFINED;
++      /* set up supported mcs set */
++      memset(&ht_info->mcs, 0, sizeof(ht_info->mcs));
++      ht_info->mcs.rx_mask[0] = 0xff;
++      ht_info->mcs.rx_mask[1] = 0xff;
++      ht_info->mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED;
+ }
+ static int ath_rate2idx(struct ath_softc *sc, int rate)
+@@ -328,31 +328,28 @@ static u8 parse_mpdudensity(u8 mpdudensi
+ static void ath9k_ht_conf(struct ath_softc *sc,
+                         struct ieee80211_bss_conf *bss_conf)
+ {
+-#define IEEE80211_HT_CAP_40MHZ_INTOLERANT BIT(14)
+       struct ath_ht_info *ht_info = &sc->sc_ht_info;
+       if (bss_conf->assoc_ht) {
+               ht_info->ext_chan_offset =
+                       bss_conf->ht_bss_conf->bss_cap &
+-                              IEEE80211_HT_IE_CHA_SEC_OFFSET;
++                              IEEE80211_HT_PARAM_CHA_SEC_OFFSET;
+-              if (!(bss_conf->ht_conf->cap &
++              if (!(bss_conf->ht_cap->cap &
+                       IEEE80211_HT_CAP_40MHZ_INTOLERANT) &&
+                           (bss_conf->ht_bss_conf->bss_cap &
+-                              IEEE80211_HT_IE_CHA_WIDTH))
++                              IEEE80211_HT_PARAM_CHAN_WIDTH_ANY))
+                       ht_info->tx_chan_width = ATH9K_HT_MACMODE_2040;
+               else
+                       ht_info->tx_chan_width = ATH9K_HT_MACMODE_20;
+               ath9k_hw_set11nmac2040(sc->sc_ah, ht_info->tx_chan_width);
+               ht_info->maxampdu = 1 << (IEEE80211_HTCAP_MAXRXAMPDU_FACTOR +
+-                                      bss_conf->ht_conf->ampdu_factor);
++                                      bss_conf->ht_cap->ampdu_factor);
+               ht_info->mpdudensity =
+-                      parse_mpdudensity(bss_conf->ht_conf->ampdu_density);
++                      parse_mpdudensity(bss_conf->ht_cap->ampdu_density);
+       }
+-
+-#undef IEEE80211_HT_CAP_40MHZ_INTOLERANT
+ }
+ static void ath9k_bss_assoc_info(struct ath_softc *sc,
+@@ -412,7 +409,7 @@ static void ath9k_bss_assoc_info(struct 
+                       return;
+               }
+-              if (hw->conf.ht_conf.ht_supported)
++              if (hw->conf.ht_cap.ht_supported)
+                       sc->sc_ah->ah_channels[pos].chanmode =
+                               ath_get_extchanmode(sc, curchan);
+               else
+@@ -535,7 +532,7 @@ int _ath_rx_indicate(struct ath_softc *s
+       if (an) {
+               ath_rx_input(sc, an,
+-                           hw->conf.ht_conf.ht_supported,
++                           hw->conf.ht_cap.ht_supported,
+                            skb, status, &st);
+       }
+       if (!an || (st != ATH_RX_CONSUMED))
+@@ -944,7 +941,7 @@ static int ath_attach(u16 devid,
+       if (sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_HT)
+               /* Setup HT capabilities for 2.4Ghz*/
+-              setup_ht_cap(&sc->sbands[IEEE80211_BAND_2GHZ].ht_info);
++              setup_ht_cap(&sc->sbands[IEEE80211_BAND_2GHZ].ht_cap);
+       hw->wiphy->bands[IEEE80211_BAND_2GHZ] =
+               &sc->sbands[IEEE80211_BAND_2GHZ];
+@@ -959,7 +956,7 @@ static int ath_attach(u16 devid,
+               if (sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_HT)
+                       /* Setup HT capabilities for 5Ghz*/
+-                      setup_ht_cap(&sc->sbands[IEEE80211_BAND_5GHZ].ht_info);
++                      setup_ht_cap(&sc->sbands[IEEE80211_BAND_5GHZ].ht_cap);
+               hw->wiphy->bands[IEEE80211_BAND_5GHZ] =
+                       &sc->sbands[IEEE80211_BAND_5GHZ];
+@@ -1255,7 +1252,7 @@ static int ath9k_config(struct ieee80211
+               (curchan->band == IEEE80211_BAND_2GHZ) ?
+               CHANNEL_G : CHANNEL_A;
+-      if (sc->sc_curaid && hw->conf.ht_conf.ht_supported)
++      if (sc->sc_curaid && hw->conf.ht_cap.ht_supported)
+               sc->sc_ah->ah_channels[pos].chanmode =
+                       ath_get_extchanmode(sc, curchan);
+--- everything.orig/drivers/net/wireless/ath9k/rc.c    2008-10-08 20:44:48.000000000 +0200
++++ everything/drivers/net/wireless/ath9k/rc.c 2008-10-09 02:16:27.000000000 +0200
+@@ -1838,7 +1838,7 @@ void ath_rc_node_update(struct ieee80211
+       struct ath_softc *sc = hw->priv;
+       u32 capflag = 0;
+-      if (hw->conf.ht_conf.ht_supported) {
++      if (hw->conf.ht_cap.ht_supported) {
+               capflag |= ATH_RC_HT_FLAG | ATH_RC_DS_FLAG;
+               if (sc->sc_ht_info.tx_chan_width == ATH9K_HT_MACMODE_2040)
+                       capflag |= ATH_RC_CW40_FLAG;
+@@ -1910,7 +1910,7 @@ static void ath_tx_aggr_resp(struct ath_
+        */
+       si = container_of(sta, struct sta_info, sta);
+       buffersize = IEEE80211_MIN_AMPDU_BUF <<
+-              sband->ht_info.ampdu_factor; /* FIXME */
++              sband->ht_cap.ampdu_factor; /* FIXME */
+       state = si->ampdu_mlme.tid_state_tx[tidno];
+       if (state & HT_ADDBA_RECEIVED_MSK) {
+@@ -1980,7 +1980,7 @@ static void ath_get_rate(void *priv, str
+       /* Check if aggregation has to be enabled for this tid */
+-      if (hw->conf.ht_conf.ht_supported) {
++      if (hw->conf.ht_cap.ht_supported) {
+               if (ieee80211_is_data_qos(fc)) {
+                       qc = ieee80211_get_qos_ctl(hdr);
+                       tid = qc[0] & 0xf;
+@@ -2028,8 +2028,8 @@ static void ath_rate_init(void *priv, st
+       ath_setup_rates(sc, sband, sta, ath_rc_priv);
+       if (sc->hw->conf.flags & IEEE80211_CONF_SUPPORT_HT_MODE) {
+-              for (i = 0; i < MCS_SET_SIZE; i++) {
+-                      if (sc->hw->conf.ht_conf.supp_mcs_set[i/8] & (1<<(i%8)))
++              for (i = 0; i < 77; i++) {
++                      if (sc->hw->conf.ht_cap.mcs.rx_mask[i/8] & (1<<(i%8)))
+                               ath_rc_priv->neg_ht_rates.rs_rates[j++] = i;
+                       if (j == ATH_RATE_MAX)
+                               break;
+--- everything.orig/drivers/net/wireless/ath9k/recv.c  2008-10-08 20:44:48.000000000 +0200
++++ everything/drivers/net/wireless/ath9k/recv.c       2008-10-09 02:16:27.000000000 +0200
+@@ -1119,7 +1119,7 @@ int ath_rx_aggr_start(struct ath_softc *
+       sband = hw->wiphy->bands[hw->conf.channel->band];
+       buffersize = IEEE80211_MIN_AMPDU_BUF <<
+-              sband->ht_info.ampdu_factor; /* FIXME */
++              sband->ht_cap.ampdu_factor; /* FIXME */
+       rxtid = &an->an_aggr.rx.tid[tid];
+--- everything.orig/drivers/net/wireless/ath9k/xmit.c  2008-10-08 20:44:48.000000000 +0200
++++ everything/drivers/net/wireless/ath9k/xmit.c       2008-10-09 02:16:27.000000000 +0200
+@@ -300,7 +300,7 @@ static int ath_tx_prepare(struct ath_sof
+       if (ieee80211_is_data(fc) && !txctl->use_minrate) {
+               /* Enable HT only for DATA frames and not for EAPOL */
+-              txctl->ht = (hw->conf.ht_conf.ht_supported &&
++              txctl->ht = (hw->conf.ht_cap.ht_supported &&
+                           (tx_info->flags & IEEE80211_TX_CTL_AMPDU));
+               if (is_multicast_ether_addr(hdr->addr1)) {
+--- everything.orig/drivers/net/wireless/ath9k/rc.h    2008-10-08 20:44:48.000000000 +0200
++++ everything/drivers/net/wireless/ath9k/rc.h 2008-10-08 20:45:06.000000000 +0200
+@@ -59,7 +59,6 @@ struct ath_softc;
+ #define FALSE 0
+ #define ATH_RATE_MAX  30
+-#define MCS_SET_SIZE  128
+ enum ieee80211_fixed_rate_mode {
+       IEEE80211_FIXED_RATE_NONE  = 0,
+--- everything.orig/drivers/net/wireless/mac80211_hwsim.c      2008-10-08 20:44:48.000000000 +0200
++++ everything/drivers/net/wireless/mac80211_hwsim.c   2008-10-09 02:16:30.000000000 +0200
+@@ -566,19 +566,18 @@ static int __init init_mac80211_hwsim(vo
+               data->band.n_channels = ARRAY_SIZE(hwsim_channels);
+               data->band.bitrates = data->rates;
+               data->band.n_bitrates = ARRAY_SIZE(hwsim_rates);
+-              data->band.ht_info.ht_supported = 1;
+-              data->band.ht_info.cap = IEEE80211_HT_CAP_SUP_WIDTH |
++              data->band.ht_cap.ht_supported = true;
++              data->band.ht_cap.cap = IEEE80211_HT_CAP_SUP_WIDTH_20_40 |
+                       IEEE80211_HT_CAP_GRN_FLD |
+                       IEEE80211_HT_CAP_SGI_40 |
+                       IEEE80211_HT_CAP_DSSSCCK40;
+-              data->band.ht_info.ampdu_factor = 0x3;
+-              data->band.ht_info.ampdu_density = 0x6;
+-              memset(data->band.ht_info.supp_mcs_set, 0,
+-                     sizeof(data->band.ht_info.supp_mcs_set));
+-              data->band.ht_info.supp_mcs_set[0] = 0xff;
+-              data->band.ht_info.supp_mcs_set[1] = 0xff;
+-              data->band.ht_info.supp_mcs_set[12] =
+-                      IEEE80211_HT_CAP_MCS_TX_DEFINED;
++              data->band.ht_cap.ampdu_factor = 0x3;
++              data->band.ht_cap.ampdu_density = 0x6;
++              memset(&data->band.ht_cap.mcs, 0,
++                     sizeof(data->band.ht_cap.mcs));
++              data->band.ht_cap.mcs.rx_mask[0] = 0xff;
++              data->band.ht_cap.mcs.rx_mask[1] = 0xff;
++              data->band.ht_cap.mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED;
+               hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &data->band;
+               err = ieee80211_register_hw(hw);
diff --git a/package/mac80211/patches/419-mac80211-remove-antenna-sel.patch b/package/mac80211/patches/419-mac80211-remove-antenna-sel.patch
new file mode 100644 (file)
index 0000000..dbdd64a
--- /dev/null
@@ -0,0 +1,259 @@
+Subject: mac80211: kill hw.conf.antenna_sel_{rx,tx}
+
+Never actually used.
+
+Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
+---
+ drivers/net/wireless/b43/main.c            |   25 +++----------------------
+ drivers/net/wireless/b43legacy/main.c      |   18 ++----------------
+ drivers/net/wireless/p54/p54common.c       |    3 +--
+ drivers/net/wireless/rt2x00/rt2x00config.c |   20 ++++----------------
+ drivers/net/wireless/rt2x00/rt2x00dev.c    |    6 ++----
+ include/net/mac80211.h                     |    7 +------
+ net/mac80211/debugfs.c                     |    8 --------
+ net/mac80211/ieee80211_i.h                 |    2 --
+ net/mac80211/tx.c                          |    1 -
+ 9 files changed, 13 insertions(+), 77 deletions(-)
+
+--- everything.orig/net/mac80211/debugfs.c     2008-10-08 22:35:20.000000000 +0200
++++ everything/net/mac80211/debugfs.c  2008-10-08 22:35:26.000000000 +0200
+@@ -47,10 +47,6 @@ static const struct file_operations name
+ DEBUGFS_READONLY_FILE(frequency, 20, "%d",
+                     local->hw.conf.channel->center_freq);
+-DEBUGFS_READONLY_FILE(antenna_sel_tx, 20, "%d",
+-                    local->hw.conf.antenna_sel_tx);
+-DEBUGFS_READONLY_FILE(antenna_sel_rx, 20, "%d",
+-                    local->hw.conf.antenna_sel_rx);
+ DEBUGFS_READONLY_FILE(rts_threshold, 20, "%d",
+                     local->rts_threshold);
+ DEBUGFS_READONLY_FILE(fragmentation_threshold, 20, "%d",
+@@ -202,8 +198,6 @@ void debugfs_hw_add(struct ieee80211_loc
+       local->debugfs.keys = debugfs_create_dir("keys", phyd);
+       DEBUGFS_ADD(frequency);
+-      DEBUGFS_ADD(antenna_sel_tx);
+-      DEBUGFS_ADD(antenna_sel_rx);
+       DEBUGFS_ADD(rts_threshold);
+       DEBUGFS_ADD(fragmentation_threshold);
+       DEBUGFS_ADD(short_retry_limit);
+@@ -258,8 +252,6 @@ void debugfs_hw_add(struct ieee80211_loc
+ void debugfs_hw_del(struct ieee80211_local *local)
+ {
+       DEBUGFS_DEL(frequency);
+-      DEBUGFS_DEL(antenna_sel_tx);
+-      DEBUGFS_DEL(antenna_sel_rx);
+       DEBUGFS_DEL(rts_threshold);
+       DEBUGFS_DEL(fragmentation_threshold);
+       DEBUGFS_DEL(short_retry_limit);
+--- everything.orig/net/mac80211/ieee80211_i.h 2008-10-08 22:35:01.000000000 +0200
++++ everything/net/mac80211/ieee80211_i.h      2008-10-08 22:35:10.000000000 +0200
+@@ -727,8 +727,6 @@ struct ieee80211_local {
+               struct dentry *rcdir;
+               struct dentry *rcname;
+               struct dentry *frequency;
+-              struct dentry *antenna_sel_tx;
+-              struct dentry *antenna_sel_rx;
+               struct dentry *rts_threshold;
+               struct dentry *fragmentation_threshold;
+               struct dentry *short_retry_limit;
+--- everything.orig/include/net/mac80211.h     2008-10-08 22:35:30.000000000 +0200
++++ everything/include/net/mac80211.h  2008-10-08 22:39:56.000000000 +0200
+@@ -324,7 +324,7 @@ struct ieee80211_tx_altrate {
+  * @flags: transmit info flags, defined above
+  * @band: TBD
+  * @tx_rate_idx: TBD
+- * @antenna_sel_tx: TBD
++ * @antenna_sel_tx: antenna to use, 0 for automatic diversity
+  * @control: union for control data
+  * @status: union for status data
+  * @driver_data: array of driver_data pointers
+@@ -474,9 +474,6 @@ static inline int __deprecated __IEEE802
+  * @listen_interval: listen interval in units of beacon interval
+  * @flags: configuration flags defined above
+  * @power_level: requested transmit power (in dBm)
+- * @antenna_sel_tx: transmit antenna selection, 0: default/diversity,
+- *    1/2: antenna 0/1
+- * @antenna_sel_rx: receive antenna selection, like @antenna_sel_tx
+  * @ht_cap: describes current self configuration of 802.11n HT capabilities
+  * @ht_bss_conf: describes current BSS configuration of 802.11n HT parameters
+  * @channel: the channel to tune to
+@@ -488,8 +485,6 @@ struct ieee80211_conf {
+       u16 listen_interval;
+       u32 flags;
+       int power_level;
+-      u8 antenna_sel_tx;
+-      u8 antenna_sel_rx;
+       struct ieee80211_channel *channel;
+--- everything.orig/net/mac80211/tx.c  2008-10-08 22:37:05.000000000 +0200
++++ everything/net/mac80211/tx.c       2008-10-08 22:37:22.000000000 +0200
+@@ -1975,7 +1975,6 @@ struct sk_buff *ieee80211_beacon_get(str
+           sband->bitrates[rsel.rate_idx].flags & IEEE80211_RATE_SHORT_PREAMBLE)
+               info->flags |= IEEE80211_TX_CTL_SHORT_PREAMBLE;
+-      info->antenna_sel_tx = local->hw.conf.antenna_sel_tx;
+       info->control.retry_limit = 1;
+ out:
+--- everything.orig/drivers/net/wireless/b43/main.c    2008-10-08 22:40:06.000000000 +0200
++++ everything/drivers/net/wireless/b43/main.c 2008-10-08 22:40:45.000000000 +0200
+@@ -1339,25 +1339,6 @@ u8 b43_ieee80211_antenna_sanitize(struct
+       return antenna_nr;
+ }
+-static int b43_antenna_from_ieee80211(struct b43_wldev *dev, u8 antenna)
+-{
+-      antenna = b43_ieee80211_antenna_sanitize(dev, antenna);
+-      switch (antenna) {
+-      case 0:         /* default/diversity */
+-              return B43_ANTENNA_DEFAULT;
+-      case 1:         /* Antenna 0 */
+-              return B43_ANTENNA0;
+-      case 2:         /* Antenna 1 */
+-              return B43_ANTENNA1;
+-      case 3:         /* Antenna 2 */
+-              return B43_ANTENNA2;
+-      case 4:         /* Antenna 3 */
+-              return B43_ANTENNA3;
+-      default:
+-              return B43_ANTENNA_DEFAULT;
+-      }
+-}
+-
+ /* Convert a b43 antenna number value to the PHY TX control value. */
+ static u16 b43_antenna_to_phyctl(int antenna)
+ {
+@@ -1399,7 +1380,7 @@ static void b43_write_beacon_template(st
+                                 len, ram_offset, shm_size_offset, rate);
+       /* Write the PHY TX control parameters. */
+-      antenna = b43_antenna_from_ieee80211(dev, info->antenna_sel_tx);
++      antenna = B43_ANTENNA_DEFAULT;
+       antenna = b43_antenna_to_phyctl(antenna);
+       ctl = b43_shm_read16(dev, B43_SHM_SHARED, B43_SHM_SH_BEACPHYCTL);
+       /* We can't send beacons with short preamble. Would get PHY errors. */
+@@ -3399,9 +3380,9 @@ static int b43_op_config(struct ieee8021
+       }
+       /* Antennas for RX and management frame TX. */
+-      antenna = b43_antenna_from_ieee80211(dev, conf->antenna_sel_tx);
++      antenna = B43_ANTENNA_DEFAULT;
+       b43_mgmtframe_txantenna(dev, antenna);
+-      antenna = b43_antenna_from_ieee80211(dev, conf->antenna_sel_rx);
++      antenna = B43_ANTENNA_DEFAULT;
+       if (phy->ops->set_rx_antenna)
+               phy->ops->set_rx_antenna(dev, antenna);
+--- everything.orig/drivers/net/wireless/b43legacy/main.c      2008-10-08 22:41:36.000000000 +0200
++++ everything/drivers/net/wireless/b43legacy/main.c   2008-10-08 22:41:59.000000000 +0200
+@@ -2556,20 +2556,6 @@ init_failure:
+       return err;
+ }
+-static int b43legacy_antenna_from_ieee80211(u8 antenna)
+-{
+-      switch (antenna) {
+-      case 0: /* default/diversity */
+-              return B43legacy_ANTENNA_DEFAULT;
+-      case 1: /* Antenna 0 */
+-              return B43legacy_ANTENNA0;
+-      case 2: /* Antenna 1 */
+-              return B43legacy_ANTENNA1;
+-      default:
+-              return B43legacy_ANTENNA_DEFAULT;
+-      }
+-}
+-
+ static int b43legacy_op_dev_config(struct ieee80211_hw *hw,
+                                  struct ieee80211_conf *conf)
+ {
+@@ -2583,8 +2569,8 @@ static int b43legacy_op_dev_config(struc
+       int err = 0;
+       u32 savedirqs;
+-      antenna_tx = b43legacy_antenna_from_ieee80211(conf->antenna_sel_tx);
+-      antenna_rx = b43legacy_antenna_from_ieee80211(conf->antenna_sel_rx);
++      antenna_tx = B43legacy_ANTENNA_DEFAULT;
++      antenna_rx = B43legacy_ANTENNA_DEFAULT;
+       mutex_lock(&wl->mutex);
+       dev = wl->current_dev;
+--- everything.orig/drivers/net/wireless/p54/p54common.c       2008-10-08 22:43:54.000000000 +0200
++++ everything/drivers/net/wireless/p54/p54common.c    2008-10-08 22:44:12.000000000 +0200
+@@ -1211,8 +1211,7 @@ static int p54_config(struct ieee80211_h
+       struct p54_common *priv = dev->priv;
+       mutex_lock(&priv->conf_mutex);
+-      priv->rx_antenna = (conf->antenna_sel_rx == 0) ?
+-              2 : conf->antenna_sel_tx - 1;
++      priv->rx_antenna = 2; /* automatic */
+       priv->output_power = conf->power_level << 2;
+       ret = p54_set_freq(dev, cpu_to_le16(conf->channel->center_freq));
+       p54_set_vdcf(dev);
+--- everything.orig/drivers/net/wireless/rt2x00/rt2x00config.c 2008-10-08 22:44:57.000000000 +0200
++++ everything/drivers/net/wireless/rt2x00/rt2x00config.c      2008-10-08 22:45:36.000000000 +0200
+@@ -199,23 +199,15 @@ void rt2x00lib_config(struct rt2x00_dev 
+        * to work with untill the link tuner decides that an antenna
+        * switch should be performed.
+        */
+-      if (!conf->antenna_sel_rx &&
+-          default_ant->rx != ANTENNA_SW_DIVERSITY &&
++      if (default_ant->rx != ANTENNA_SW_DIVERSITY &&
+           default_ant->rx != active_ant->rx)
+               flags |= CONFIG_UPDATE_ANTENNA;
+-      else if (conf->antenna_sel_rx &&
+-               conf->antenna_sel_rx != active_ant->rx)
+-              flags |= CONFIG_UPDATE_ANTENNA;
+       else if (active_ant->rx == ANTENNA_SW_DIVERSITY)
+               flags |= CONFIG_UPDATE_ANTENNA;
+-      if (!conf->antenna_sel_tx &&
+-          default_ant->tx != ANTENNA_SW_DIVERSITY &&
++      if (default_ant->tx != ANTENNA_SW_DIVERSITY &&
+           default_ant->tx != active_ant->tx)
+               flags |= CONFIG_UPDATE_ANTENNA;
+-      else if (conf->antenna_sel_tx &&
+-               conf->antenna_sel_tx != active_ant->tx)
+-              flags |= CONFIG_UPDATE_ANTENNA;
+       else if (active_ant->tx == ANTENNA_SW_DIVERSITY)
+               flags |= CONFIG_UPDATE_ANTENNA;
+@@ -252,18 +244,14 @@ config:
+       }
+       if (flags & CONFIG_UPDATE_ANTENNA) {
+-              if (conf->antenna_sel_rx)
+-                      libconf.ant.rx = conf->antenna_sel_rx;
+-              else if (default_ant->rx != ANTENNA_SW_DIVERSITY)
++              if (default_ant->rx != ANTENNA_SW_DIVERSITY)
+                       libconf.ant.rx = default_ant->rx;
+               else if (active_ant->rx == ANTENNA_SW_DIVERSITY)
+                       libconf.ant.rx = ANTENNA_B;
+               else
+                       libconf.ant.rx = active_ant->rx;
+-              if (conf->antenna_sel_tx)
+-                      libconf.ant.tx = conf->antenna_sel_tx;
+-              else if (default_ant->tx != ANTENNA_SW_DIVERSITY)
++              if (default_ant->tx != ANTENNA_SW_DIVERSITY)
+                       libconf.ant.tx = default_ant->tx;
+               else if (active_ant->tx == ANTENNA_SW_DIVERSITY)
+                       libconf.ant.tx = ANTENNA_B;
+--- everything.orig/drivers/net/wireless/rt2x00/rt2x00dev.c    2008-10-08 22:44:28.000000000 +0200
++++ everything/drivers/net/wireless/rt2x00/rt2x00dev.c 2008-10-08 22:44:43.000000000 +0200
+@@ -249,11 +249,9 @@ static void rt2x00lib_evaluate_antenna(s
+       rt2x00dev->link.ant.flags &= ~ANTENNA_RX_DIVERSITY;
+       rt2x00dev->link.ant.flags &= ~ANTENNA_TX_DIVERSITY;
+-      if (rt2x00dev->hw->conf.antenna_sel_rx == 0 &&
+-          rt2x00dev->default_ant.rx == ANTENNA_SW_DIVERSITY)
++      if (rt2x00dev->default_ant.rx == ANTENNA_SW_DIVERSITY)
+               rt2x00dev->link.ant.flags |= ANTENNA_RX_DIVERSITY;
+-      if (rt2x00dev->hw->conf.antenna_sel_tx == 0 &&
+-          rt2x00dev->default_ant.tx == ANTENNA_SW_DIVERSITY)
++      if (rt2x00dev->default_ant.tx == ANTENNA_SW_DIVERSITY)
+               rt2x00dev->link.ant.flags |= ANTENNA_TX_DIVERSITY;
+       if (!(rt2x00dev->link.ant.flags & ANTENNA_RX_DIVERSITY) &&
diff --git a/package/mac80211/patches/420-mac80211-hw-conf-change-flags.patch b/package/mac80211/patches/420-mac80211-hw-conf-change-flags.patch
new file mode 100644 (file)
index 0000000..4bae8cb
--- /dev/null
@@ -0,0 +1,616 @@
+Subject: mac80211: introduce hw config change flags
+
+This makes mac80211 notify the driver which configuration
+actually changed, e.g. channel etc.
+
+No driver changes, this is just plumbing, driver authors are
+expected to act on this if they want to.
+
+Also remove the HW CONFIG debug printk, it's incorrect, often
+we configure something else.
+
+Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
+---
+ drivers/net/wireless/adm8211.c              |    3 +-
+ drivers/net/wireless/at76_usb.c             |    3 +-
+ drivers/net/wireless/ath5k/base.c           |    7 ++----
+ drivers/net/wireless/ath9k/main.c           |    4 +--
+ drivers/net/wireless/b43/main.c             |    3 +-
+ drivers/net/wireless/b43legacy/main.c       |    3 +-
+ drivers/net/wireless/iwlwifi/iwl-agn.c      |    3 +-
+ drivers/net/wireless/iwlwifi/iwl3945-base.c |    7 +++---
+ drivers/net/wireless/libertas_tf/main.c     |    4 ++-
+ drivers/net/wireless/mac80211_hwsim.c       |    4 +--
+ drivers/net/wireless/p54/p54common.c        |    3 +-
+ drivers/net/wireless/rt2x00/rt2x00.h        |    2 -
+ drivers/net/wireless/rt2x00/rt2x00dev.c     |    2 -
+ drivers/net/wireless/rt2x00/rt2x00mac.c     |    3 +-
+ drivers/net/wireless/rtl8180_dev.c          |    3 +-
+ drivers/net/wireless/rtl8187_dev.c          |    3 +-
+ drivers/net/wireless/zd1211rw/zd_mac.c      |    4 ++-
+ include/net/mac80211.h                      |   30 +++++++++++++++++++++++-----
+ net/mac80211/cfg.c                          |    3 +-
+ net/mac80211/ieee80211_i.h                  |    2 -
+ net/mac80211/iface.c                        |   25 +++++++++++++++++------
+ net/mac80211/main.c                         |   29 ++++++++++++++-------------
+ net/mac80211/scan.c                         |   12 ++++++++---
+ net/mac80211/util.c                         |    3 +-
+ net/mac80211/wext.c                         |   14 ++++++-------
+ 25 files changed, 118 insertions(+), 61 deletions(-)
+
+--- a/include/net/mac80211.h
++++ b/include/net/mac80211.h
+@@ -464,12 +464,32 @@ static inline int __deprecated __IEEE802
+ #define IEEE80211_CONF_SHORT_SLOT_TIME (__IEEE80211_CONF_SHORT_SLOT_TIME())
+ /**
++ * enum ieee80211_conf_changed - denotes which configuration changed
++ *
++ * @IEEE80211_CONF_CHANGE_RADIO_ENABLED: the value of radio_enabled changed
++ * @IEEE80211_CONF_CHANGE_BEACON_INTERVAL: the beacon interval changed
++ * @IEEE80211_CONF_CHANGE_LISTEN_INTERVAL: the listen interval changed
++ * @IEEE80211_CONF_CHANGE_RADIOTAP: the radiotap flag changed
++ * @IEEE80211_CONF_CHANGE_PS: the PS flag changed
++ * @IEEE80211_CONF_CHANGE_POWER: the TX power changed
++ * @IEEE80211_CONF_CHANGE_CHANNEL: the channel changed
++ */
++enum ieee80211_conf_changed {
++      IEEE80211_CONF_CHANGE_RADIO_ENABLED     = BIT(0),
++      IEEE80211_CONF_CHANGE_BEACON_INTERVAL   = BIT(1),
++      IEEE80211_CONF_CHANGE_LISTEN_INTERVAL   = BIT(2),
++      IEEE80211_CONF_CHANGE_RADIOTAP          = BIT(3),
++      IEEE80211_CONF_CHANGE_PS                = BIT(4),
++      IEEE80211_CONF_CHANGE_POWER             = BIT(5),
++      IEEE80211_CONF_CHANGE_CHANNEL           = BIT(6),
++};
++
++/**
+  * struct ieee80211_conf - configuration of the device
+  *
+  * This struct indicates how the driver shall configure the hardware.
+  *
+  * @radio_enabled: when zero, driver is required to switch off the radio.
+- *    TODO make a flag
+  * @beacon_int: beacon interval (TODO make interface config)
+  * @listen_interval: listen interval in units of beacon interval
+  * @flags: configuration flags defined above
+@@ -479,13 +499,13 @@ static inline int __deprecated __IEEE802
+  * @channel: the channel to tune to
+  */
+ struct ieee80211_conf {
+-      int radio_enabled;
+-
+       int beacon_int;
+-      u16 listen_interval;
+       u32 flags;
+       int power_level;
++      u16 listen_interval;
++      bool radio_enabled;
++
+       struct ieee80211_channel *channel;
+       struct ieee80211_sta_ht_cap ht_cap;
+@@ -1213,7 +1233,7 @@ struct ieee80211_ops {
+                            struct ieee80211_if_init_conf *conf);
+       void (*remove_interface)(struct ieee80211_hw *hw,
+                                struct ieee80211_if_init_conf *conf);
+-      int (*config)(struct ieee80211_hw *hw, struct ieee80211_conf *conf);
++      int (*config)(struct ieee80211_hw *hw, u32 changed);
+       int (*config_interface)(struct ieee80211_hw *hw,
+                               struct ieee80211_vif *vif,
+                               struct ieee80211_if_conf *conf);
+--- a/net/mac80211/cfg.c
++++ b/net/mac80211/cfg.c
+@@ -394,7 +394,8 @@ static int ieee80211_config_beacon(struc
+        */
+       if (params->interval) {
+               sdata->local->hw.conf.beacon_int = params->interval;
+-              ieee80211_hw_config(sdata->local);
++              ieee80211_hw_config(sdata->local,
++                                  IEEE80211_CONF_CHANGE_BEACON_INTERVAL);
+               /*
+                * We updated some parameter so if below bails out
+                * it's not an error.
+--- a/net/mac80211/ieee80211_i.h
++++ b/net/mac80211/ieee80211_i.h
+@@ -880,7 +880,7 @@ static inline int ieee80211_bssid_match(
+ }
+-int ieee80211_hw_config(struct ieee80211_local *local);
++int ieee80211_hw_config(struct ieee80211_local *local, u32 changed);
+ int ieee80211_if_config(struct ieee80211_sub_if_data *sdata, u32 changed);
+ void ieee80211_tx_set_protected(struct ieee80211_tx_data *tx);
+ void ieee80211_bss_info_change_notify(struct ieee80211_sub_if_data *sdata,
+--- a/net/mac80211/iface.c
++++ b/net/mac80211/iface.c
+@@ -65,7 +65,7 @@ static int ieee80211_open(struct net_dev
+       struct ieee80211_if_init_conf conf;
+       u32 changed = 0;
+       int res;
+-      bool need_hw_reconfig = 0;
++      u32 hw_reconf_flags = 0;
+       u8 null_addr[ETH_ALEN] = {0};
+       /* fail early if user set an invalid address */
+@@ -152,7 +152,8 @@ static int ieee80211_open(struct net_dev
+                       res = local->ops->start(local_to_hw(local));
+               if (res)
+                       goto err_del_bss;
+-              need_hw_reconfig = 1;
++              /* we're brought up, everything changes */
++              hw_reconf_flags = ~0;
+               ieee80211_led_radio(local, local->hw.conf.radio_enabled);
+       }
+@@ -198,8 +199,10 @@ static int ieee80211_open(struct net_dev
+               /* must be before the call to ieee80211_configure_filter */
+               local->monitors++;
+-              if (local->monitors == 1)
++              if (local->monitors == 1) {
+                       local->hw.conf.flags |= IEEE80211_CONF_RADIOTAP;
++                      hw_reconf_flags |= IEEE80211_CONF_CHANGE_RADIOTAP;
++              }
+               if (sdata->u.mntr_flags & MONITOR_FLAG_FCSFAIL)
+                       local->fif_fcsfail++;
+@@ -279,8 +282,8 @@ static int ieee80211_open(struct net_dev
+               atomic_inc(&local->iff_promiscs);
+       local->open_count++;
+-      if (need_hw_reconfig) {
+-              ieee80211_hw_config(local);
++      if (hw_reconf_flags) {
++              ieee80211_hw_config(local, hw_reconf_flags);
+               /*
+                * set default queue parameters so drivers don't
+                * need to initialise the hardware if the hardware
+@@ -322,6 +325,7 @@ static int ieee80211_stop(struct net_dev
+       struct ieee80211_local *local = sdata->local;
+       struct ieee80211_if_init_conf conf;
+       struct sta_info *sta;
++      u32 hw_reconf_flags = 0;
+       /*
+        * Stop TX on this interface first.
+@@ -405,8 +409,10 @@ static int ieee80211_stop(struct net_dev
+               }
+               local->monitors--;
+-              if (local->monitors == 0)
++              if (local->monitors == 0) {
+                       local->hw.conf.flags &= ~IEEE80211_CONF_RADIOTAP;
++                      hw_reconf_flags |= IEEE80211_CONF_CHANGE_RADIOTAP;
++              }
+               if (sdata->u.mntr_flags & MONITOR_FLAG_FCSFAIL)
+                       local->fif_fcsfail--;
+@@ -504,8 +510,15 @@ static int ieee80211_stop(struct net_dev
+               tasklet_disable(&local->tx_pending_tasklet);
+               tasklet_disable(&local->tasklet);
++
++              /* no reconfiguring after stop! */
++              hw_reconf_flags = 0;
+       }
++      /* do after stop to avoid reconfiguring when we stop anyway */
++      if (hw_reconf_flags)
++              ieee80211_hw_config(local, hw_reconf_flags);
++
+       return 0;
+ }
+--- a/net/mac80211/main.c
++++ b/net/mac80211/main.c
+@@ -197,31 +197,34 @@ int ieee80211_if_config(struct ieee80211
+                                           &sdata->vif, &conf);
+ }
+-int ieee80211_hw_config(struct ieee80211_local *local)
++int ieee80211_hw_config(struct ieee80211_local *local, u32 changed)
+ {
+       struct ieee80211_channel *chan;
+       int ret = 0;
++      int power;
+       if (local->sw_scanning)
+               chan = local->scan_channel;
+       else
+               chan = local->oper_channel;
+-      local->hw.conf.channel = chan;
++      if (chan != local->hw.conf.channel) {
++              local->hw.conf.channel = chan;
++              changed |= IEEE80211_CONF_CHANGE_CHANNEL;
++      }
++
+       if (!local->hw.conf.power_level)
+-              local->hw.conf.power_level = chan->max_power;
++              power = chan->max_power;
+       else
+-              local->hw.conf.power_level = min(chan->max_power,
+-                                             local->hw.conf.power_level);
+-
+-#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
+-      printk(KERN_DEBUG "%s: HW CONFIG: freq=%d\n",
+-             wiphy_name(local->hw.wiphy), chan->center_freq);
+-#endif
++              power = min(chan->max_power, local->hw.conf.power_level);
++      if (local->hw.conf.power_level != power) {
++              changed |= IEEE80211_CONF_CHANGE_POWER;
++              local->hw.conf.power_level = power;
++      }
+-      if (local->open_count) {
+-              ret = local->ops->config(local_to_hw(local), &local->hw.conf);
++      if (changed && local->open_count) {
++              ret = local->ops->config(local_to_hw(local), changed);
+               /*
+                * HW reconfiguration should never fail, the driver has told
+                * us what it can support so it should live up to that promise.
+@@ -672,7 +675,7 @@ struct ieee80211_hw *ieee80211_alloc_hw(
+       local->fragmentation_threshold = IEEE80211_MAX_FRAG_THRESHOLD;
+       local->short_retry_limit = 7;
+       local->long_retry_limit = 4;
+-      local->hw.conf.radio_enabled = 1;
++      local->hw.conf.radio_enabled = true;
+       INIT_LIST_HEAD(&local->interfaces);
+--- a/net/mac80211/scan.c
++++ b/net/mac80211/scan.c
+@@ -447,12 +447,17 @@ void ieee80211_scan_completed(struct iee
+       if (local->hw_scanning) {
+               local->hw_scanning = false;
+-              ieee80211_hw_config(local);
++              /*
++               * Somebody might have requested channel change during scan
++               * that we won't have acted upon, try now. ieee80211_hw_config
++               * will set the flag based on actual changes.
++               */
++              ieee80211_hw_config(local, 0);
+               goto done;
+       }
+       local->sw_scanning = false;
+-      ieee80211_hw_config(local);
++      ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL);
+       netif_tx_lock_bh(local->mdev);
+       netif_addr_lock(local->mdev);
+@@ -539,7 +544,8 @@ void ieee80211_scan_work(struct work_str
+               if (!skip) {
+                       local->scan_channel = chan;
+-                      if (ieee80211_hw_config(local))
++                      if (ieee80211_hw_config(local,
++                                              IEEE80211_CONF_CHANGE_CHANNEL))
+                               skip = 1;
+               }
+--- a/net/mac80211/util.c
++++ b/net/mac80211/util.c
+@@ -645,7 +645,8 @@ int ieee80211_set_freq(struct ieee80211_
+               if (local->sw_scanning || local->hw_scanning)
+                       ret = 0;
+               else
+-                      ret = ieee80211_hw_config(local);
++                      ret = ieee80211_hw_config(
++                              local, IEEE80211_CONF_CHANGE_CHANNEL);
+               rate_control_clear(local);
+       }
+--- a/net/mac80211/wext.c
++++ b/net/mac80211/wext.c
+@@ -656,7 +656,7 @@ static int ieee80211_ioctl_siwtxpower(st
+                                     union iwreq_data *data, char *extra)
+ {
+       struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+-      bool need_reconfig = 0;
++      u32 reconf_flags = 0;
+       int new_power_level;
+       if ((data->txpower.flags & IW_TXPOW_TYPE) != IW_TXPOW_DBM)
+@@ -680,17 +680,17 @@ static int ieee80211_ioctl_siwtxpower(st
+       if (local->hw.conf.power_level != new_power_level) {
+               local->hw.conf.power_level = new_power_level;
+-              need_reconfig = 1;
++              reconf_flags |= IEEE80211_CONF_CHANGE_POWER;
+       }
+       if (local->hw.conf.radio_enabled != !(data->txpower.disabled)) {
+               local->hw.conf.radio_enabled = !(data->txpower.disabled);
+-              need_reconfig = 1;
++              reconf_flags |= IEEE80211_CONF_CHANGE_RADIO_ENABLED;
+               ieee80211_led_radio(local, local->hw.conf.radio_enabled);
+       }
+-      if (need_reconfig)
+-              ieee80211_hw_config(local);
++      if (reconf_flags)
++              ieee80211_hw_config(local, reconf_flags);
+       return 0;
+ }
+@@ -976,7 +976,7 @@ static int ieee80211_ioctl_siwpower(stru
+       if (wrq->disabled) {
+               conf->flags &= ~IEEE80211_CONF_PS;
+-              return ieee80211_hw_config(local);
++              return ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS);
+       }
+       switch (wrq->flags & IW_POWER_MODE) {
+@@ -989,7 +989,7 @@ static int ieee80211_ioctl_siwpower(stru
+               return -EINVAL;
+       }
+-      return ieee80211_hw_config(local);
++      return ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS);
+ }
+ static int ieee80211_ioctl_giwpower(struct net_device *dev,
+--- a/drivers/net/wireless/adm8211.c
++++ b/drivers/net/wireless/adm8211.c
+@@ -1314,9 +1314,10 @@ static int adm8211_set_ssid(struct ieee8
+       return 0;
+ }
+-static int adm8211_config(struct ieee80211_hw *dev, struct ieee80211_conf *conf)
++static int adm8211_config(struct ieee80211_hw *dev, u32 changed)
+ {
+       struct adm8211_priv *priv = dev->priv;
++      struct ieee80211_conf *conf = &dev->conf;
+       int channel = ieee80211_frequency_to_channel(conf->channel->center_freq);
+       if (channel != priv->channel) {
+--- a/drivers/net/wireless/at76_usb.c
++++ b/drivers/net/wireless/at76_usb.c
+@@ -2057,9 +2057,10 @@ exit:
+       return 0;
+ }
+-static int at76_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf)
++static int at76_config(struct ieee80211_hw *hw, u32 changed)
+ {
+       struct at76_priv *priv = hw->priv;
++      struct ieee80211_conf *conf = &hw->conf;
+       at76_dbg(DBG_MAC80211, "%s(): channel %d radio %d",
+                __func__, conf->channel->hw_value, conf->radio_enabled);
+--- a/drivers/net/wireless/ath5k/base.c
++++ b/drivers/net/wireless/ath5k/base.c
+@@ -219,8 +219,7 @@ static int ath5k_add_interface(struct ie
+               struct ieee80211_if_init_conf *conf);
+ static void ath5k_remove_interface(struct ieee80211_hw *hw,
+               struct ieee80211_if_init_conf *conf);
+-static int ath5k_config(struct ieee80211_hw *hw,
+-              struct ieee80211_conf *conf);
++static int ath5k_config(struct ieee80211_hw *hw, u32 changed);
+ static int ath5k_config_interface(struct ieee80211_hw *hw,
+               struct ieee80211_vif *vif,
+               struct ieee80211_if_conf *conf);
+@@ -2767,10 +2766,10 @@ end:
+  * TODO: Phy disable/diversity etc
+  */
+ static int
+-ath5k_config(struct ieee80211_hw *hw,
+-                      struct ieee80211_conf *conf)
++ath5k_config(struct ieee80211_hw *hw, u32 changed)
+ {
+       struct ath5k_softc *sc = hw->priv;
++      struct ieee80211_conf *conf = &hw->conf;
+       sc->bintval = conf->beacon_int;
+       sc->power_level = conf->power_level;
+--- a/drivers/net/wireless/ath9k/main.c
++++ b/drivers/net/wireless/ath9k/main.c
+@@ -1231,11 +1231,11 @@ static void ath9k_remove_interface(struc
+                       __func__, error);
+ }
+-static int ath9k_config(struct ieee80211_hw *hw,
+-                      struct ieee80211_conf *conf)
++static int ath9k_config(struct ieee80211_hw *hw, u32 changed)
+ {
+       struct ath_softc *sc = hw->priv;
+       struct ieee80211_channel *curchan = hw->conf.channel;
++      struct ieee80211_conf *conf = &hw->conf;
+       int pos;
+       DPRINTF(sc, ATH_DBG_CONFIG, "%s: Set channel: %d MHz\n",
+--- a/drivers/net/wireless/b43/main.c
++++ b/drivers/net/wireless/b43/main.c
+@@ -3320,11 +3320,12 @@ init_failure:
+       return err;
+ }
+-static int b43_op_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf)
++static int b43_op_config(struct ieee80211_hw *hw, u32 changed)
+ {
+       struct b43_wl *wl = hw_to_b43_wl(hw);
+       struct b43_wldev *dev;
+       struct b43_phy *phy;
++      struct ieee80211_conf *conf = &hw->conf;
+       unsigned long flags;
+       int antenna;
+       int err = 0;
+--- a/drivers/net/wireless/b43legacy/main.c
++++ b/drivers/net/wireless/b43legacy/main.c
+@@ -2557,11 +2557,12 @@ init_failure:
+ }
+ static int b43legacy_op_dev_config(struct ieee80211_hw *hw,
+-                                 struct ieee80211_conf *conf)
++                                 u32 changed)
+ {
+       struct b43legacy_wl *wl = hw_to_b43legacy_wl(hw);
+       struct b43legacy_wldev *dev;
+       struct b43legacy_phy *phy;
++      struct ieee80211_conf *conf = &hw->conf;
+       unsigned long flags;
+       unsigned int new_phymode = 0xFFFF;
+       int antenna_tx;
+--- a/drivers/net/wireless/iwlwifi/iwl-agn.c
++++ b/drivers/net/wireless/iwlwifi/iwl-agn.c
+@@ -2760,10 +2760,11 @@ static int iwl4965_mac_add_interface(str
+  * be set inappropriately and the driver currently sets the hardware up to
+  * use it whenever needed.
+  */
+-static int iwl4965_mac_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf)
++static int iwl4965_mac_config(struct ieee80211_hw *hw, u32 changed)
+ {
+       struct iwl_priv *priv = hw->priv;
+       const struct iwl_channel_info *ch_info;
++      struct ieee80211_conf *conf = &hw->conf;
+       unsigned long flags;
+       int ret = 0;
+       u16 channel;
+--- a/drivers/net/wireless/iwlwifi/iwl3945-base.c
++++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c
+@@ -6427,7 +6427,7 @@ static void iwl3945_bg_abort_scan(struct
+       mutex_unlock(&priv->mutex);
+ }
+-static int iwl3945_mac_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf);
++static int iwl3945_mac_config(struct ieee80211_hw *hw, u32 changed);
+ static void iwl3945_bg_scan_completed(struct work_struct *work)
+ {
+@@ -6440,7 +6440,7 @@ static void iwl3945_bg_scan_completed(st
+               return;
+       if (test_bit(STATUS_CONF_PENDING, &priv->status))
+-              iwl3945_mac_config(priv->hw, ieee80211_get_hw_conf(priv->hw));
++              iwl3945_mac_config(priv->hw, 0);
+       ieee80211_scan_completed(priv->hw);
+@@ -6629,10 +6629,11 @@ static int iwl3945_mac_add_interface(str
+  * be set inappropriately and the driver currently sets the hardware up to
+  * use it whenever needed.
+  */
+-static int iwl3945_mac_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf)
++static int iwl3945_mac_config(struct ieee80211_hw *hw, u32 changed)
+ {
+       struct iwl3945_priv *priv = hw->priv;
+       const struct iwl3945_channel_info *ch_info;
++      struct ieee80211_conf *conf = &hw->conf;
+       unsigned long flags;
+       int ret = 0;
+--- a/drivers/net/wireless/mac80211_hwsim.c
++++ b/drivers/net/wireless/mac80211_hwsim.c
+@@ -361,10 +361,10 @@ static void mac80211_hwsim_beacon(unsign
+ }
+-static int mac80211_hwsim_config(struct ieee80211_hw *hw,
+-                               struct ieee80211_conf *conf)
++static int mac80211_hwsim_config(struct ieee80211_hw *hw, u32 changed)
+ {
+       struct mac80211_hwsim_data *data = hw->priv;
++      struct ieee80211_conf *conf = &hw->conf;
+       printk(KERN_DEBUG "%s:%s (freq=%d radio_enabled=%d beacon_int=%d)\n",
+              wiphy_name(hw->wiphy), __func__,
+--- a/drivers/net/wireless/p54/p54common.c
++++ b/drivers/net/wireless/p54/p54common.c
+@@ -1205,10 +1205,11 @@ static void p54_remove_interface(struct 
+       p54_set_filter(dev, 0, NULL);
+ }
+-static int p54_config(struct ieee80211_hw *dev, struct ieee80211_conf *conf)
++static int p54_config(struct ieee80211_hw *dev, u32 changed)
+ {
+       int ret;
+       struct p54_common *priv = dev->priv;
++      struct ieee80211_conf *conf = &dev->conf;
+       mutex_lock(&priv->conf_mutex);
+       priv->rx_antenna = 2; /* automatic */
+--- a/drivers/net/wireless/rt2x00/rt2x00.h
++++ b/drivers/net/wireless/rt2x00/rt2x00.h
+@@ -997,7 +997,7 @@ int rt2x00mac_add_interface(struct ieee8
+                           struct ieee80211_if_init_conf *conf);
+ void rt2x00mac_remove_interface(struct ieee80211_hw *hw,
+                               struct ieee80211_if_init_conf *conf);
+-int rt2x00mac_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf);
++int rt2x00mac_config(struct ieee80211_hw *hw, u32 changed);
+ int rt2x00mac_config_interface(struct ieee80211_hw *hw,
+                              struct ieee80211_vif *vif,
+                              struct ieee80211_if_conf *conf);
+--- a/drivers/net/wireless/rt2x00/rt2x00mac.c
++++ b/drivers/net/wireless/rt2x00/rt2x00mac.c
+@@ -335,9 +335,10 @@ void rt2x00mac_remove_interface(struct i
+ }
+ EXPORT_SYMBOL_GPL(rt2x00mac_remove_interface);
+-int rt2x00mac_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf)
++int rt2x00mac_config(struct ieee80211_hw *hw, u32 changed)
+ {
+       struct rt2x00_dev *rt2x00dev = hw->priv;
++      struct ieee80211_conf *conf = &hw->conf;
+       int radio_on;
+       int status;
+--- a/drivers/net/wireless/rtl8180_dev.c
++++ b/drivers/net/wireless/rtl8180_dev.c
+@@ -692,9 +692,10 @@ static void rtl8180_remove_interface(str
+       priv->vif = NULL;
+ }
+-static int rtl8180_config(struct ieee80211_hw *dev, struct ieee80211_conf *conf)
++static int rtl8180_config(struct ieee80211_hw *dev, u32 changed)
+ {
+       struct rtl8180_priv *priv = dev->priv;
++      struct ieee80211_conf *conf = &dev->conf;
+       priv->rf->set_chan(dev, conf);
+--- a/drivers/net/wireless/rtl8187_dev.c
++++ b/drivers/net/wireless/rtl8187_dev.c
+@@ -870,9 +870,10 @@ static void rtl8187_remove_interface(str
+       mutex_unlock(&priv->conf_mutex);
+ }
+-static int rtl8187_config(struct ieee80211_hw *dev, struct ieee80211_conf *conf)
++static int rtl8187_config(struct ieee80211_hw *dev, u32 changed)
+ {
+       struct rtl8187_priv *priv = dev->priv;
++      struct ieee80211_conf *conf = &dev->conf;
+       u32 reg;
+       mutex_lock(&priv->conf_mutex);
+--- a/drivers/net/wireless/zd1211rw/zd_mac.c
++++ b/drivers/net/wireless/zd1211rw/zd_mac.c
+@@ -743,9 +743,11 @@ static void zd_op_remove_interface(struc
+       zd_write_mac_addr(&mac->chip, NULL);
+ }
+-static int zd_op_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf)
++static int zd_op_config(struct ieee80211_hw *hw, u32 changed)
+ {
+       struct zd_mac *mac = zd_hw_mac(hw);
++      struct ieee80211_conf *conf = &hw->conf;
++
+       return zd_chip_set_channel(&mac->chip, conf->channel->hw_value);
+ }
+--- a/drivers/net/wireless/rt2x00/rt2x00dev.c
++++ b/drivers/net/wireless/rt2x00/rt2x00dev.c
+@@ -1245,7 +1245,7 @@ int rt2x00lib_resume(struct rt2x00_dev *
+       /*
+        * Reconfigure device.
+        */
+-      retval = rt2x00mac_config(rt2x00dev->hw, &rt2x00dev->hw->conf);
++      retval = rt2x00mac_config(rt2x00dev->hw, ~0);
+       if (retval)
+               goto exit;
diff --git a/package/mac80211/patches/421-nl80211-export-ht.patch b/package/mac80211/patches/421-nl80211-export-ht.patch
new file mode 100644 (file)
index 0000000..d6f6b5a
--- /dev/null
@@ -0,0 +1,64 @@
+Subject: nl80211: export HT capabilities
+
+This exports the local HT capabilities in nl80211.
+
+Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
+---
+ include/linux/nl80211.h |   12 ++++++++++++
+ net/wireless/nl80211.c  |   13 +++++++++++++
+ 2 files changed, 25 insertions(+)
+
+--- everything.orig/include/linux/nl80211.h    2008-10-09 01:31:09.000000000 +0200
++++ everything/include/linux/nl80211.h 2008-10-09 02:11:44.000000000 +0200
+@@ -452,17 +452,29 @@ enum nl80211_mpath_info {
+  *    an array of nested frequency attributes
+  * @NL80211_BAND_ATTR_RATES: supported bitrates in this band,
+  *    an array of nested bitrate attributes
++ * @NL80211_BAND_ATTR_HT_MCS_SET: 16-byte attribute containing the MCS set as
++ *    defined in 802.11n
++ * @NL80211_BAND_ATTR_HT_CAPA: HT capabilities, as in the HT information IE
++ * @NL80211_BAND_ATTR_HT_AMPDU_FACTOR: A-MPDU factor, as in 11n
++ * @NL80211_BAND_ATTR_HT_AMPDU_DENSITY: A-MPDU density, as in 11n
+  */
+ enum nl80211_band_attr {
+       __NL80211_BAND_ATTR_INVALID,
+       NL80211_BAND_ATTR_FREQS,
+       NL80211_BAND_ATTR_RATES,
++      NL80211_BAND_ATTR_HT_MCS_SET,
++      NL80211_BAND_ATTR_HT_CAPA,
++      NL80211_BAND_ATTR_HT_AMPDU_FACTOR,
++      NL80211_BAND_ATTR_HT_AMPDU_DENSITY,
++
+       /* keep last */
+       __NL80211_BAND_ATTR_AFTER_LAST,
+       NL80211_BAND_ATTR_MAX = __NL80211_BAND_ATTR_AFTER_LAST - 1
+ };
++#define NL80211_BAND_ATTR_HT_CAPA NL80211_BAND_ATTR_HT_CAPA
++
+ /**
+  * enum nl80211_frequency_attr - frequency attributes
+  * @NL80211_FREQUENCY_ATTR_FREQ: Frequency in MHz
+--- everything.orig/net/wireless/nl80211.c     2008-10-09 01:32:05.000000000 +0200
++++ everything/net/wireless/nl80211.c  2008-10-09 02:12:21.000000000 +0200
+@@ -157,6 +157,19 @@ static int nl80211_send_wiphy(struct sk_
+               if (!nl_band)
+                       goto nla_put_failure;
++              /* add HT info */
++              if (dev->wiphy.bands[band]->ht_cap.ht_supported) {
++                      NLA_PUT(msg, NL80211_BAND_ATTR_HT_MCS_SET,
++                              sizeof(dev->wiphy.bands[band]->ht_cap.mcs),
++                              &dev->wiphy.bands[band]->ht_cap.mcs);
++                      NLA_PUT_U16(msg, NL80211_BAND_ATTR_HT_CAPA,
++                              dev->wiphy.bands[band]->ht_cap.cap);
++                      NLA_PUT_U8(msg, NL80211_BAND_ATTR_HT_AMPDU_FACTOR,
++                              dev->wiphy.bands[band]->ht_cap.ampdu_factor);
++                      NLA_PUT_U8(msg, NL80211_BAND_ATTR_HT_AMPDU_DENSITY,
++                              dev->wiphy.bands[band]->ht_cap.ampdu_density);
++              }
++
+               /* add frequencies */
+               nl_freqs = nla_nest_start(msg, NL80211_BAND_ATTR_FREQS);
+               if (!nl_freqs)
diff --git a/package/mac80211/patches/422-mac80211-seqno-station.patch b/package/mac80211/patches/422-mac80211-seqno-station.patch
new file mode 100644 (file)
index 0000000..72fbd9c
--- /dev/null
@@ -0,0 +1,142 @@
+Subject: mac80211: provide sequence numbers
+
+I've come to think that not providing sequence numbers for
+the normal STA mode case was a mistake, at least two drivers
+now had to implement code they wouldn't otherwise need, and
+I believe at76_usb and adm8211 might be broken.
+
+This patch makes mac80211 assign a sequence number to all
+those frames that need one except beacons. That means that
+if a driver only implements modes that do not do beaconing
+it need not worry about the sequence number.
+
+Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
+---
+ drivers/net/wireless/p54/p54.h       |    1 -
+ drivers/net/wireless/p54/p54common.c |   18 +++++-------------
+ drivers/net/wireless/rtl8187.h       |    1 -
+ drivers/net/wireless/rtl8187_dev.c   |   18 ++++--------------
+ net/mac80211/ieee80211_i.h           |    2 ++
+ net/mac80211/tx.c                    |   10 ++++++++++
+ 6 files changed, 21 insertions(+), 29 deletions(-)
+
+--- everything.orig/net/mac80211/ieee80211_i.h 2008-10-10 15:45:52.000000000 +0200
++++ everything/net/mac80211/ieee80211_i.h      2008-10-10 15:45:56.000000000 +0200
+@@ -438,6 +438,8 @@ struct ieee80211_sub_if_data {
+       struct ieee80211_key *keys[NUM_DEFAULT_KEYS];
+       struct ieee80211_key *default_key;
++      u16 sequence_number;
++
+       /* BSS configuration for this interface. */
+       struct ieee80211_bss_conf bss_conf;
+--- everything.orig/net/mac80211/tx.c  2008-10-10 15:45:48.000000000 +0200
++++ everything/net/mac80211/tx.c       2008-10-10 15:45:56.000000000 +0200
+@@ -602,8 +602,18 @@ ieee80211_tx_h_sequence(struct ieee80211
+       if (ieee80211_hdrlen(hdr->frame_control) < 24)
+               return TX_CONTINUE;
++      /*
++       * Anything but QoS data that has a sequence number field
++       * (is long enough) gets a sequence number from the global
++       * counter.
++       */
+       if (!ieee80211_is_data_qos(hdr->frame_control)) {
++              /* driver should assign sequence number */
+               info->flags |= IEEE80211_TX_CTL_ASSIGN_SEQ;
++              /* for pure STA mode without beacons, we can do it */
++              hdr->seq_ctrl = cpu_to_le16(tx->sdata->sequence_number);
++              tx->sdata->sequence_number += 0x10;
++              tx->sdata->sequence_number &= IEEE80211_SCTL_SEQ;
+               return TX_CONTINUE;
+       }
+--- everything.orig/drivers/net/wireless/p54/p54.h     2008-10-10 15:45:49.000000000 +0200
++++ everything/drivers/net/wireless/p54/p54.h  2008-10-10 15:45:56.000000000 +0200
+@@ -67,7 +67,6 @@ struct p54_common {
+       int (*open)(struct ieee80211_hw *dev);
+       void (*stop)(struct ieee80211_hw *dev);
+       int mode;
+-      u16 seqno;
+       u16 rx_mtu;
+       u8 headroom;
+       u8 tailroom;
+--- everything.orig/drivers/net/wireless/p54/p54common.c       2008-10-10 15:45:49.000000000 +0200
++++ everything/drivers/net/wireless/p54/p54common.c    2008-10-10 15:45:56.000000000 +0200
+@@ -865,19 +865,6 @@ static int p54_tx(struct ieee80211_hw *d
+       if (padding)
+               txhdr->align[0] = padding;
+-      /* FIXME: The sequence that follows is needed for this driver to
+-       * work with mac80211 since "mac80211: fix TX sequence numbers".
+-       * As with the temporary code in rt2x00, changes will be needed
+-       * to get proper sequence numbers on beacons. In addition, this
+-       * patch places the sequence number in the hardware state, which
+-       * limits us to a single virtual state.
+-       */
+-      if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) {
+-              if (info->flags & IEEE80211_TX_CTL_FIRST_FRAGMENT)
+-                      priv->seqno += 0x10;
+-              ieee80211hdr->seq_ctrl &= cpu_to_le16(IEEE80211_SCTL_FRAG);
+-              ieee80211hdr->seq_ctrl |= cpu_to_le16(priv->seqno);
+-      }
+       /* modifies skb->cb and with it info, so must be last! */
+       p54_assign_address(dev, skb, hdr, skb->len);
+@@ -1391,6 +1378,11 @@ struct ieee80211_hw *p54_init_common(siz
+                    IEEE80211_HW_SIGNAL_DBM |
+                    IEEE80211_HW_NOISE_DBM;
++      /*
++       * XXX: when this driver gets support for any mode that
++       *      requires beacons (AP, MESH, IBSS) then it must
++       *      implement IEEE80211_TX_CTL_ASSIGN_SEQ.
++       */
+       dev->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION);
+       dev->channel_change_time = 1000;        /* TODO: find actual value */
+--- everything.orig/drivers/net/wireless/rtl8187_dev.c 2008-10-10 15:45:49.000000000 +0200
++++ everything/drivers/net/wireless/rtl8187_dev.c      2008-10-10 15:45:56.000000000 +0200
+@@ -238,20 +238,6 @@ static int rtl8187_tx(struct ieee80211_h
+                       ep = epmap[skb_get_queue_mapping(skb)];
+       }
+-      /* FIXME: The sequence that follows is needed for this driver to
+-       * work with mac80211 since "mac80211: fix TX sequence numbers".
+-       * As with the temporary code in rt2x00, changes will be needed
+-       * to get proper sequence numbers on beacons. In addition, this
+-       * patch places the sequence number in the hardware state, which
+-       * limits us to a single virtual state.
+-       */
+-      if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) {
+-              if (info->flags & IEEE80211_TX_CTL_FIRST_FRAGMENT)
+-                      priv->seqno += 0x10;
+-              ieee80211hdr->seq_ctrl &= cpu_to_le16(IEEE80211_SCTL_FRAG);
+-              ieee80211hdr->seq_ctrl |= cpu_to_le16(priv->seqno);
+-      }
+-
+       info->driver_data[0] = dev;
+       info->driver_data[1] = urb;
+@@ -1185,6 +1171,10 @@ static int __devinit rtl8187_probe(struc
+               dev->max_signal = 65;
+       }
++      /*
++       * XXX: Once this driver supports anything that requires
++       *      beacons it must implement IEEE80211_TX_CTL_ASSIGN_SEQ.
++       */
+       dev->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION);
+       if ((id->driver_info == DEVICE_RTL8187) && priv->is_rtl8187b)
+--- everything.orig/drivers/net/wireless/rtl8187.h     2008-10-10 15:45:49.000000000 +0200
++++ everything/drivers/net/wireless/rtl8187.h  2008-10-10 15:45:56.000000000 +0200
+@@ -100,7 +100,6 @@ struct rtl8187_priv {
+       struct usb_device *udev;
+       u32 rx_conf;
+       u16 txpwr_base;
+-      u16 seqno;
+       u8 asic_rev;
+       u8 is_rtl8187b;
+       enum {
diff --git a/package/mac80211/patches/423-mac80211-make-bss-conf-part-of-vif.patch b/package/mac80211/patches/423-mac80211-make-bss-conf-part-of-vif.patch
new file mode 100644 (file)
index 0000000..556d651
--- /dev/null
@@ -0,0 +1,303 @@
+Subject: mac80211: move bss_conf into vif
+
+Move bss_conf into the vif struct so that drivers can
+access it during ->tx without having to store it in
+the private data or similar. No driver updates because
+this is only for when they want to start using it.
+
+Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
+---
+ include/net/mac80211.h        |    3 +++
+ net/mac80211/cfg.c            |    6 +++---
+ net/mac80211/debugfs_netdev.c |    2 +-
+ net/mac80211/ieee80211_i.h    |    3 ---
+ net/mac80211/iface.c          |    2 +-
+ net/mac80211/main.c           |    8 ++++----
+ net/mac80211/mlme.c           |   30 +++++++++++++++---------------
+ net/mac80211/tx.c             |   16 ++++++++--------
+ net/mac80211/util.c           |    6 +++---
+ 9 files changed, 38 insertions(+), 38 deletions(-)
+
+--- everything.orig/include/net/mac80211.h     2008-10-10 17:09:04.000000000 +0200
++++ everything/include/net/mac80211.h  2008-10-10 17:09:41.000000000 +0200
+@@ -519,11 +519,14 @@ struct ieee80211_conf {
+  * use during the life of a virtual interface.
+  *
+  * @type: type of this virtual interface
++ * @bss_conf: BSS configuration for this interface, either our own
++ *    or the BSS we're associated to
+  * @drv_priv: data area for driver use, will always be aligned to
+  *    sizeof(void *).
+  */
+ struct ieee80211_vif {
+       enum nl80211_iftype type;
++      struct ieee80211_bss_conf bss_conf;
+       /* must be last */
+       u8 drv_priv[0] __attribute__((__aligned__(sizeof(void *))));
+ };
+--- everything.orig/net/mac80211/ieee80211_i.h 2008-10-10 17:10:40.000000000 +0200
++++ everything/net/mac80211/ieee80211_i.h      2008-10-10 17:10:45.000000000 +0200
+@@ -440,9 +440,6 @@ struct ieee80211_sub_if_data {
+       u16 sequence_number;
+-      /* BSS configuration for this interface. */
+-      struct ieee80211_bss_conf bss_conf;
+-
+       /*
+        * AP this belongs to: self in AP mode and
+        * corresponding AP in VLAN mode, NULL for
+--- everything.orig/net/mac80211/main.c        2008-10-10 17:10:55.000000000 +0200
++++ everything/net/mac80211/main.c     2008-10-10 17:11:10.000000000 +0200
+@@ -249,15 +249,15 @@ void ieee80211_bss_info_change_notify(st
+       if (local->ops->bss_info_changed)
+               local->ops->bss_info_changed(local_to_hw(local),
+                                            &sdata->vif,
+-                                           &sdata->bss_conf,
++                                           &sdata->vif.bss_conf,
+                                            changed);
+ }
+ u32 ieee80211_reset_erp_info(struct ieee80211_sub_if_data *sdata)
+ {
+-      sdata->bss_conf.use_cts_prot = false;
+-      sdata->bss_conf.use_short_preamble = false;
+-      sdata->bss_conf.use_short_slot = false;
++      sdata->vif.bss_conf.use_cts_prot = false;
++      sdata->vif.bss_conf.use_short_preamble = false;
++      sdata->vif.bss_conf.use_short_slot = false;
+       return BSS_CHANGED_ERP_CTS_PROT |
+              BSS_CHANGED_ERP_PREAMBLE |
+              BSS_CHANGED_ERP_SLOT;
+--- everything.orig/net/mac80211/iface.c       2008-10-10 17:12:11.000000000 +0200
++++ everything/net/mac80211/iface.c    2008-10-10 17:12:13.000000000 +0200
+@@ -695,7 +695,7 @@ int ieee80211_if_change_type(struct ieee
+       ieee80211_setup_sdata(sdata, type);
+       /* reset some values that shouldn't be kept across type changes */
+-      sdata->bss_conf.basic_rates =
++      sdata->vif.bss_conf.basic_rates =
+               ieee80211_mandatory_rates(sdata->local,
+                       sdata->local->hw.conf.channel->band);
+       sdata->drop_unencrypted = 0;
+--- everything.orig/net/mac80211/mlme.c        2008-10-10 17:11:49.000000000 +0200
++++ everything/net/mac80211/mlme.c     2008-10-10 17:11:58.000000000 +0200
+@@ -572,7 +572,7 @@ static void ieee80211_sta_wmm_params(str
+ static u32 ieee80211_handle_bss_capability(struct ieee80211_sub_if_data *sdata,
+                                          u16 capab, bool erp_valid, u8 erp)
+ {
+-      struct ieee80211_bss_conf *bss_conf = &sdata->bss_conf;
++      struct ieee80211_bss_conf *bss_conf = &sdata->vif.bss_conf;
+ #ifdef CONFIG_MAC80211_VERBOSE_DEBUG
+       struct ieee80211_if_sta *ifsta = &sdata->u.sta;
+       DECLARE_MAC_BUF(mac);
+@@ -720,9 +720,9 @@ static void ieee80211_set_associated(str
+                                  ifsta->ssid, ifsta->ssid_len);
+       if (bss) {
+               /* set timing information */
+-              sdata->bss_conf.beacon_int = bss->beacon_int;
+-              sdata->bss_conf.timestamp = bss->timestamp;
+-              sdata->bss_conf.dtim_period = bss->dtim_period;
++              sdata->vif.bss_conf.beacon_int = bss->beacon_int;
++              sdata->vif.bss_conf.timestamp = bss->timestamp;
++              sdata->vif.bss_conf.dtim_period = bss->dtim_period;
+               changed |= ieee80211_handle_bss_capability(sdata,
+                       bss->capability, bss->has_erp_value, bss->erp_value);
+@@ -732,9 +732,9 @@ static void ieee80211_set_associated(str
+       if (conf->flags & IEEE80211_CONF_SUPPORT_HT_MODE) {
+               changed |= BSS_CHANGED_HT;
+-              sdata->bss_conf.assoc_ht = 1;
+-              sdata->bss_conf.ht_cap = &conf->ht_cap;
+-              sdata->bss_conf.ht_bss_conf = &conf->ht_bss_conf;
++              sdata->vif.bss_conf.assoc_ht = 1;
++              sdata->vif.bss_conf.ht_cap = &conf->ht_cap;
++              sdata->vif.bss_conf.ht_bss_conf = &conf->ht_bss_conf;
+       }
+       ifsta->flags |= IEEE80211_STA_PREV_BSSID_SET;
+@@ -744,7 +744,7 @@ static void ieee80211_set_associated(str
+       ifsta->last_probe = jiffies;
+       ieee80211_led_assoc(local, 1);
+-      sdata->bss_conf.assoc = 1;
++      sdata->vif.bss_conf.assoc = 1;
+       /*
+        * For now just always ask the driver to update the basic rateset
+        * when we have associated, we aren't checking whether it actually
+@@ -853,15 +853,15 @@ static void ieee80211_set_disassoc(struc
+       ifsta->flags &= ~IEEE80211_STA_ASSOCIATED;
+       changed |= ieee80211_reset_erp_info(sdata);
+-      if (sdata->bss_conf.assoc_ht)
++      if (sdata->vif.bss_conf.assoc_ht)
+               changed |= BSS_CHANGED_HT;
+-      sdata->bss_conf.assoc_ht = 0;
+-      sdata->bss_conf.ht_cap = NULL;
+-      sdata->bss_conf.ht_bss_conf = NULL;
++      sdata->vif.bss_conf.assoc_ht = 0;
++      sdata->vif.bss_conf.ht_cap = NULL;
++      sdata->vif.bss_conf.ht_bss_conf = NULL;
+       ieee80211_led_assoc(local, 0);
+-      sdata->bss_conf.assoc = 0;
++      sdata->vif.bss_conf.assoc = 0;
+       ieee80211_sta_send_apinfo(sdata, ifsta);
+@@ -1194,7 +1194,7 @@ static void ieee80211_rx_mgmt_assoc_resp
+       u64 rates, basic_rates;
+       u16 capab_info, status_code, aid;
+       struct ieee802_11_elems elems;
+-      struct ieee80211_bss_conf *bss_conf = &sdata->bss_conf;
++      struct ieee80211_bss_conf *bss_conf = &sdata->vif.bss_conf;
+       u8 *pos;
+       int i, j;
+       DECLARE_MAC_BUF(mac);
+@@ -1337,7 +1337,7 @@ static void ieee80211_rx_mgmt_assoc_resp
+       }
+       sta->sta.supp_rates[local->hw.conf.channel->band] = rates;
+-      sdata->bss_conf.basic_rates = basic_rates;
++      sdata->vif.bss_conf.basic_rates = basic_rates;
+       /* cf. IEEE 802.11 9.2.12 */
+       if (local->hw.conf.channel->band == IEEE80211_BAND_2GHZ &&
+--- everything.orig/net/mac80211/cfg.c 2008-10-10 17:12:29.000000000 +0200
++++ everything/net/mac80211/cfg.c      2008-10-10 17:12:31.000000000 +0200
+@@ -966,16 +966,16 @@ static int ieee80211_change_bss(struct w
+               return -EINVAL;
+       if (params->use_cts_prot >= 0) {
+-              sdata->bss_conf.use_cts_prot = params->use_cts_prot;
++              sdata->vif.bss_conf.use_cts_prot = params->use_cts_prot;
+               changed |= BSS_CHANGED_ERP_CTS_PROT;
+       }
+       if (params->use_short_preamble >= 0) {
+-              sdata->bss_conf.use_short_preamble =
++              sdata->vif.bss_conf.use_short_preamble =
+                       params->use_short_preamble;
+               changed |= BSS_CHANGED_ERP_PREAMBLE;
+       }
+       if (params->use_short_slot_time >= 0) {
+-              sdata->bss_conf.use_short_slot =
++              sdata->vif.bss_conf.use_short_slot =
+                       params->use_short_slot_time;
+               changed |= BSS_CHANGED_ERP_SLOT;
+       }
+--- everything.orig/net/mac80211/debugfs_netdev.c      2008-10-10 17:13:26.000000000 +0200
++++ everything/net/mac80211/debugfs_netdev.c   2008-10-10 17:13:28.000000000 +0200
+@@ -120,7 +120,7 @@ static ssize_t ieee80211_if_fmt_flags(
+                sdata->u.sta.flags & IEEE80211_STA_AUTHENTICATED ? "AUTH\n" : "",
+                sdata->u.sta.flags & IEEE80211_STA_ASSOCIATED ? "ASSOC\n" : "",
+                sdata->u.sta.flags & IEEE80211_STA_PROBEREQ_POLL ? "PROBEREQ POLL\n" : "",
+-               sdata->bss_conf.use_cts_prot ? "CTS prot\n" : "");
++               sdata->vif.bss_conf.use_cts_prot ? "CTS prot\n" : "");
+ }
+ __IEEE80211_IF_FILE(flags);
+--- everything.orig/net/mac80211/tx.c  2008-10-10 17:12:46.000000000 +0200
++++ everything/net/mac80211/tx.c       2008-10-10 17:12:49.000000000 +0200
+@@ -116,7 +116,7 @@ static __le16 ieee80211_duration(struct 
+               if (r->bitrate > txrate->bitrate)
+                       break;
+-              if (tx->sdata->bss_conf.basic_rates & BIT(i))
++              if (tx->sdata->vif.bss_conf.basic_rates & BIT(i))
+                       rate = r->bitrate;
+               switch (sband->band) {
+@@ -150,7 +150,7 @@ static __le16 ieee80211_duration(struct 
+        * to closest integer */
+       dur = ieee80211_frame_duration(local, 10, rate, erp,
+-                              tx->sdata->bss_conf.use_short_preamble);
++                              tx->sdata->vif.bss_conf.use_short_preamble);
+       if (next_frag_len) {
+               /* Frame is fragmented: duration increases with time needed to
+@@ -159,7 +159,7 @@ static __le16 ieee80211_duration(struct 
+               /* next fragment */
+               dur += ieee80211_frame_duration(local, next_frag_len,
+                               txrate->bitrate, erp,
+-                              tx->sdata->bss_conf.use_short_preamble);
++                              tx->sdata->vif.bss_conf.use_short_preamble);
+       }
+       return cpu_to_le16(dur);
+@@ -465,7 +465,7 @@ ieee80211_tx_h_rate_ctrl(struct ieee8021
+       } else
+               info->control.retries[0].rate_idx = -1;
+-      if (tx->sdata->bss_conf.use_cts_prot &&
++      if (tx->sdata->vif.bss_conf.use_cts_prot &&
+           (tx->flags & IEEE80211_TX_FRAGMENTED) && (rsel.nonerp_idx >= 0)) {
+               tx->last_frag_rate_idx = tx->rate_idx;
+               if (rsel.probe_idx >= 0)
+@@ -531,7 +531,7 @@ ieee80211_tx_h_misc(struct ieee80211_tx_
+       if ((tx->sdata->flags & IEEE80211_SDATA_OPERATING_GMODE) &&
+           (sband->bitrates[tx->rate_idx].flags & IEEE80211_RATE_ERP_G) &&
+           (tx->flags & IEEE80211_TX_UNICAST) &&
+-          tx->sdata->bss_conf.use_cts_prot &&
++          tx->sdata->vif.bss_conf.use_cts_prot &&
+           !(info->flags & IEEE80211_TX_CTL_USE_RTS_CTS))
+               info->flags |= IEEE80211_TX_CTL_USE_CTS_PROTECT;
+@@ -540,7 +540,7 @@ ieee80211_tx_h_misc(struct ieee80211_tx_
+        * available on the network at the current point in time. */
+       if (ieee80211_is_data(hdr->frame_control) &&
+           (sband->bitrates[tx->rate_idx].flags & IEEE80211_RATE_SHORT_PREAMBLE) &&
+-          tx->sdata->bss_conf.use_short_preamble &&
++          tx->sdata->vif.bss_conf.use_short_preamble &&
+           (!tx->sta || test_sta_flags(tx->sta, WLAN_STA_SHORT_PREAMBLE))) {
+               info->flags |= IEEE80211_TX_CTL_SHORT_PREAMBLE;
+       }
+@@ -560,7 +560,7 @@ ieee80211_tx_h_misc(struct ieee80211_tx_
+               for (idx = 0; idx < sband->n_bitrates; idx++) {
+                       if (sband->bitrates[idx].bitrate > rate->bitrate)
+                               continue;
+-                      if (tx->sdata->bss_conf.basic_rates & BIT(idx) &&
++                      if (tx->sdata->vif.bss_conf.basic_rates & BIT(idx) &&
+                           (baserate < 0 ||
+                            (sband->bitrates[baserate].bitrate
+                             < sband->bitrates[idx].bitrate)))
+@@ -1981,7 +1981,7 @@ struct sk_buff *ieee80211_beacon_get(str
+       info->flags |= IEEE80211_TX_CTL_NO_ACK;
+       info->flags |= IEEE80211_TX_CTL_CLEAR_PS_FILT;
+       info->flags |= IEEE80211_TX_CTL_ASSIGN_SEQ;
+-      if (sdata->bss_conf.use_short_preamble &&
++      if (sdata->vif.bss_conf.use_short_preamble &&
+           sband->bitrates[rsel.rate_idx].flags & IEEE80211_RATE_SHORT_PREAMBLE)
+               info->flags |= IEEE80211_TX_CTL_SHORT_PREAMBLE;
+--- everything.orig/net/mac80211/util.c        2008-10-10 17:13:03.000000000 +0200
++++ everything/net/mac80211/util.c     2008-10-10 17:13:06.000000000 +0200
+@@ -239,7 +239,7 @@ __le16 ieee80211_generic_frame_duration(
+       erp = 0;
+       if (vif) {
+               sdata = vif_to_sdata(vif);
+-              short_preamble = sdata->bss_conf.use_short_preamble;
++              short_preamble = sdata->vif.bss_conf.use_short_preamble;
+               if (sdata->flags & IEEE80211_SDATA_OPERATING_GMODE)
+                       erp = rate->flags & IEEE80211_RATE_ERP_G;
+       }
+@@ -272,7 +272,7 @@ __le16 ieee80211_rts_duration(struct iee
+       erp = 0;
+       if (vif) {
+               sdata = vif_to_sdata(vif);
+-              short_preamble = sdata->bss_conf.use_short_preamble;
++              short_preamble = sdata->vif.bss_conf.use_short_preamble;
+               if (sdata->flags & IEEE80211_SDATA_OPERATING_GMODE)
+                       erp = rate->flags & IEEE80211_RATE_ERP_G;
+       }
+@@ -312,7 +312,7 @@ __le16 ieee80211_ctstoself_duration(stru
+       erp = 0;
+       if (vif) {
+               sdata = vif_to_sdata(vif);
+-              short_preamble = sdata->bss_conf.use_short_preamble;
++              short_preamble = sdata->vif.bss_conf.use_short_preamble;
+               if (sdata->flags & IEEE80211_SDATA_OPERATING_GMODE)
+                       erp = rate->flags & IEEE80211_RATE_ERP_G;
+       }
diff --git a/package/mac80211/patches/424-mac80211-make-retry-limits-available.patch b/package/mac80211/patches/424-mac80211-make-retry-limits-available.patch
new file mode 100644 (file)
index 0000000..084ed9a
--- /dev/null
@@ -0,0 +1,506 @@
+---
+ drivers/net/wireless/ath9k/main.c       |    1 
+ drivers/net/wireless/b43/main.c         |   67 +++++++++++++-----------------
+ drivers/net/wireless/b43legacy/main.c   |   70 ++++++++++++++------------------
+ drivers/net/wireless/rt2x00/rt2400pci.c |    2 
+ drivers/net/wireless/rt2x00/rt2500pci.c |    2 
+ drivers/net/wireless/rt2x00/rt2x00.h    |    3 +
+ drivers/net/wireless/rt2x00/rt2x00mac.c |    9 ++++
+ drivers/net/wireless/rt2x00/rt61pci.c   |    2 
+ drivers/net/wireless/rt2x00/rt73usb.c   |    2 
+ include/net/mac80211.h                  |   14 ++++--
+ net/mac80211/debugfs.c                  |    4 -
+ net/mac80211/ieee80211_i.h              |    2 
+ net/mac80211/main.c                     |    4 -
+ net/mac80211/tx.c                       |    4 -
+ net/mac80211/wext.c                     |   28 +++++-------
+ 15 files changed, 106 insertions(+), 108 deletions(-)
+
+--- everything.orig/include/net/mac80211.h     2008-10-10 23:27:46.000000000 +0200
++++ everything/include/net/mac80211.h  2008-10-10 23:31:21.000000000 +0200
+@@ -473,6 +473,7 @@ static inline int __deprecated __IEEE802
+  * @IEEE80211_CONF_CHANGE_PS: the PS flag changed
+  * @IEEE80211_CONF_CHANGE_POWER: the TX power changed
+  * @IEEE80211_CONF_CHANGE_CHANNEL: the channel changed
++ * @IEEE80211_CONF_CHANGE_RETRY_LIMITS: retry limits changed
+  */
+ enum ieee80211_conf_changed {
+       IEEE80211_CONF_CHANGE_RADIO_ENABLED     = BIT(0),
+@@ -482,6 +483,7 @@ enum ieee80211_conf_changed {
+       IEEE80211_CONF_CHANGE_PS                = BIT(4),
+       IEEE80211_CONF_CHANGE_POWER             = BIT(5),
+       IEEE80211_CONF_CHANGE_CHANNEL           = BIT(6),
++      IEEE80211_CONF_CHANGE_RETRY_LIMITS      = BIT(7),
+ };
+ /**
+@@ -497,6 +499,12 @@ enum ieee80211_conf_changed {
+  * @ht_cap: describes current self configuration of 802.11n HT capabilities
+  * @ht_bss_conf: describes current BSS configuration of 802.11n HT parameters
+  * @channel: the channel to tune to
++ * @long_frame_max_tx_count: Maximum number of transmissions for a "long" frame
++ *    (a frame not RTS protected), called "dot11LongRetryLimit" in 802.11,
++ *    but actually means the number of transmissions not the number of retries
++ * @short_frame_max_tx_count: Maximum number of transmissions for a "short" frame,
++ *    called "dot11ShortRetryLimit" in 802.11, but actually means the number
++ *    of transmissions not the number of retries
+  */
+ struct ieee80211_conf {
+       int beacon_int;
+@@ -506,6 +514,8 @@ struct ieee80211_conf {
+       u16 listen_interval;
+       bool radio_enabled;
++      u8 long_frame_max_tx_count, short_frame_max_tx_count;
++
+       struct ieee80211_channel *channel;
+       struct ieee80211_sta_ht_cap ht_cap;
+@@ -1192,8 +1202,6 @@ enum ieee80211_ampdu_mlme_action {
+  *    the device does fragmentation by itself; if this method is assigned then
+  *    the stack will not do fragmentation.
+  *
+- * @set_retry_limit: Configuration of retry limits (if device needs it)
+- *
+  * @sta_notify: Notifies low level driver about addition or removal
+  *    of assocaited station or AP.
+  *
+@@ -1263,8 +1271,6 @@ struct ieee80211_ops {
+                            u32 *iv32, u16 *iv16);
+       int (*set_rts_threshold)(struct ieee80211_hw *hw, u32 value);
+       int (*set_frag_threshold)(struct ieee80211_hw *hw, u32 value);
+-      int (*set_retry_limit)(struct ieee80211_hw *hw,
+-                             u32 short_retry, u32 long_retr);
+       void (*sta_notify)(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+                       enum sta_notify_cmd, struct ieee80211_sta *sta);
+       int (*conf_tx)(struct ieee80211_hw *hw, u16 queue,
+--- everything.orig/net/mac80211/ieee80211_i.h 2008-10-10 23:27:46.000000000 +0200
++++ everything/net/mac80211/ieee80211_i.h      2008-10-10 23:31:22.000000000 +0200
+@@ -632,8 +632,6 @@ struct ieee80211_local {
+       int rts_threshold;
+       int fragmentation_threshold;
+-      int short_retry_limit; /* dot11ShortRetryLimit */
+-      int long_retry_limit; /* dot11LongRetryLimit */
+       struct crypto_blkcipher *wep_tx_tfm;
+       struct crypto_blkcipher *wep_rx_tfm;
+--- everything.orig/net/mac80211/main.c        2008-10-10 23:27:46.000000000 +0200
++++ everything/net/mac80211/main.c     2008-10-10 23:31:22.000000000 +0200
+@@ -673,8 +673,8 @@ struct ieee80211_hw *ieee80211_alloc_hw(
+       local->rts_threshold = IEEE80211_MAX_RTS_THRESHOLD;
+       local->fragmentation_threshold = IEEE80211_MAX_FRAG_THRESHOLD;
+-      local->short_retry_limit = 7;
+-      local->long_retry_limit = 4;
++      local->hw.conf.long_frame_max_tx_count = 4;
++      local->hw.conf.short_frame_max_tx_count = 7;
+       local->hw.conf.radio_enabled = true;
+       INIT_LIST_HEAD(&local->interfaces);
+--- everything.orig/net/mac80211/wext.c        2008-10-10 23:27:46.000000000 +0200
++++ everything/net/mac80211/wext.c     2008-10-10 23:31:22.000000000 +0200
+@@ -802,21 +802,16 @@ static int ieee80211_ioctl_siwretry(stru
+           (retry->flags & IW_RETRY_TYPE) != IW_RETRY_LIMIT)
+               return -EINVAL;
+-      if (retry->flags & IW_RETRY_MAX)
+-              local->long_retry_limit = retry->value;
+-      else if (retry->flags & IW_RETRY_MIN)
+-              local->short_retry_limit = retry->value;
+-      else {
+-              local->long_retry_limit = retry->value;
+-              local->short_retry_limit = retry->value;
++      if (retry->flags & IW_RETRY_MAX) {
++              local->hw.conf.long_frame_max_tx_count = retry->value;
++      } else if (retry->flags & IW_RETRY_MIN) {
++              local->hw.conf.short_frame_max_tx_count = retry->value;
++      } else {
++              local->hw.conf.long_frame_max_tx_count = retry->value;
++              local->hw.conf.short_frame_max_tx_count = retry->value;
+       }
+-      if (local->ops->set_retry_limit) {
+-              return local->ops->set_retry_limit(
+-                      local_to_hw(local),
+-                      local->short_retry_limit,
+-                      local->long_retry_limit);
+-      }
++      ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_RETRY_LIMITS);
+       return 0;
+ }
+@@ -833,14 +828,15 @@ static int ieee80211_ioctl_giwretry(stru
+               /* first return min value, iwconfig will ask max value
+                * later if needed */
+               retry->flags |= IW_RETRY_LIMIT;
+-              retry->value = local->short_retry_limit;
+-              if (local->long_retry_limit != local->short_retry_limit)
++              retry->value = local->hw.conf.short_frame_max_tx_count;
++              if (local->hw.conf.long_frame_max_tx_count !=
++                  local->hw.conf.short_frame_max_tx_count)
+                       retry->flags |= IW_RETRY_MIN;
+               return 0;
+       }
+       if (retry->flags & IW_RETRY_MAX) {
+               retry->flags = IW_RETRY_LIMIT | IW_RETRY_MAX;
+-              retry->value = local->long_retry_limit;
++              retry->value = local->hw.conf.long_frame_max_tx_count;
+       }
+       return 0;
+--- everything.orig/drivers/net/wireless/ath9k/main.c  2008-10-10 23:27:47.000000000 +0200
++++ everything/drivers/net/wireless/ath9k/main.c       2008-10-10 23:31:23.000000000 +0200
+@@ -1657,7 +1657,6 @@ static struct ieee80211_ops ath9k_ops = 
+       .get_tkip_seq       = NULL,
+       .set_rts_threshold  = NULL,
+       .set_frag_threshold = NULL,
+-      .set_retry_limit    = NULL,
+       .get_tsf            = ath9k_get_tsf,
+       .reset_tsf          = ath9k_reset_tsf,
+       .tx_last_beacon     = NULL,
+--- everything.orig/drivers/net/wireless/b43/main.c    2008-10-10 23:27:47.000000000 +0200
++++ everything/drivers/net/wireless/b43/main.c 2008-10-10 23:31:23.000000000 +0200
+@@ -3320,6 +3320,22 @@ init_failure:
+       return err;
+ }
++/* Write the short and long frame retry limit values. */
++static void b43_set_retry_limits(struct b43_wldev *dev,
++                               unsigned int short_retry,
++                               unsigned int long_retry)
++{
++      /* The retry limit is a 4-bit counter. Enforce this to avoid overflowing
++       * the chip-internal counter. */
++      short_retry = min(short_retry, (unsigned int)0xF);
++      long_retry = min(long_retry, (unsigned int)0xF);
++
++      b43_shm_write16(dev, B43_SHM_SCRATCH, B43_SHM_SC_SRLIMIT,
++                      short_retry);
++      b43_shm_write16(dev, B43_SHM_SCRATCH, B43_SHM_SC_LRLIMIT,
++                      long_retry);
++}
++
+ static int b43_op_config(struct ieee80211_hw *hw, u32 changed)
+ {
+       struct b43_wl *wl = hw_to_b43_wl(hw);
+@@ -3333,6 +3349,20 @@ static int b43_op_config(struct ieee8021
+       mutex_lock(&wl->mutex);
++      if (changed & IEEE80211_CONF_CHANGE_RETRY_LIMITS) {
++              dev = wl->current_dev;
++              if (unlikely(!dev || (b43_status(dev) < B43_STAT_INITIALIZED))) {
++                      err = -ENODEV;
++                      goto out_unlock_mutex;
++              }
++              b43_set_retry_limits(dev, conf->short_frame_max_tx_count,
++                                        conf->long_frame_max_tx_count);
++              changed &= ~IEEE80211_CONF_CHANGE_RETRY_LIMITS;
++      }
++
++      if (!changed)
++              goto out_unlock_mutex;
++
+       /* Switch the band (if necessary). This might change the active core. */
+       err = b43_switch_band(wl, conf->channel);
+       if (err)
+@@ -3860,22 +3890,6 @@ static void b43_imcfglo_timeouts_workaro
+ #endif /* CONFIG_SSB_DRIVER_PCICORE */
+ }
+-/* Write the short and long frame retry limit values. */
+-static void b43_set_retry_limits(struct b43_wldev *dev,
+-                               unsigned int short_retry,
+-                               unsigned int long_retry)
+-{
+-      /* The retry limit is a 4-bit counter. Enforce this to avoid overflowing
+-       * the chip-internal counter. */
+-      short_retry = min(short_retry, (unsigned int)0xF);
+-      long_retry = min(long_retry, (unsigned int)0xF);
+-
+-      b43_shm_write16(dev, B43_SHM_SCRATCH, B43_SHM_SC_SRLIMIT,
+-                      short_retry);
+-      b43_shm_write16(dev, B43_SHM_SCRATCH, B43_SHM_SC_LRLIMIT,
+-                      long_retry);
+-}
+-
+ static void b43_set_synth_pu_delay(struct b43_wldev *dev, bool idle)
+ {
+       u16 pu_delay;
+@@ -4196,26 +4210,6 @@ static void b43_op_stop(struct ieee80211
+       cancel_work_sync(&(wl->txpower_adjust_work));
+ }
+-static int b43_op_set_retry_limit(struct ieee80211_hw *hw,
+-                                u32 short_retry_limit, u32 long_retry_limit)
+-{
+-      struct b43_wl *wl = hw_to_b43_wl(hw);
+-      struct b43_wldev *dev;
+-      int err = 0;
+-
+-      mutex_lock(&wl->mutex);
+-      dev = wl->current_dev;
+-      if (unlikely(!dev || (b43_status(dev) < B43_STAT_INITIALIZED))) {
+-              err = -ENODEV;
+-              goto out_unlock;
+-      }
+-      b43_set_retry_limits(dev, short_retry_limit, long_retry_limit);
+-out_unlock:
+-      mutex_unlock(&wl->mutex);
+-
+-      return err;
+-}
+-
+ static int b43_op_beacon_set_tim(struct ieee80211_hw *hw,
+                                struct ieee80211_sta *sta, bool set)
+ {
+@@ -4252,7 +4246,6 @@ static const struct ieee80211_ops b43_hw
+       .get_tx_stats           = b43_op_get_tx_stats,
+       .start                  = b43_op_start,
+       .stop                   = b43_op_stop,
+-      .set_retry_limit        = b43_op_set_retry_limit,
+       .set_tim                = b43_op_beacon_set_tim,
+       .sta_notify             = b43_op_sta_notify,
+ };
+--- everything.orig/drivers/net/wireless/b43legacy/main.c      2008-10-10 23:27:47.000000000 +0200
++++ everything/drivers/net/wireless/b43legacy/main.c   2008-10-10 23:31:23.000000000 +0200
+@@ -2556,6 +2556,20 @@ init_failure:
+       return err;
+ }
++/* Write the short and long frame retry limit values. */
++static void b43legacy_set_retry_limits(struct b43legacy_wldev *dev,
++                                     unsigned int short_retry,
++                                     unsigned int long_retry)
++{
++      /* The retry limit is a 4-bit counter. Enforce this to avoid overflowing
++       * the chip-internal counter. */
++      short_retry = min(short_retry, (unsigned int)0xF);
++      long_retry = min(long_retry, (unsigned int)0xF);
++
++      b43legacy_shm_write16(dev, B43legacy_SHM_WIRELESS, 0x0006, short_retry);
++      b43legacy_shm_write16(dev, B43legacy_SHM_WIRELESS, 0x0007, long_retry);
++}
++
+ static int b43legacy_op_dev_config(struct ieee80211_hw *hw,
+                                  u32 changed)
+ {
+@@ -2570,10 +2584,27 @@ static int b43legacy_op_dev_config(struc
+       int err = 0;
+       u32 savedirqs;
++      mutex_lock(&wl->mutex);
++      dev = wl->current_dev;
++
++      if (changed & IEEE80211_CONF_CHANGE_RETRY_LIMITS) {
++              if (unlikely(!dev ||
++                           (b43legacy_status(dev) < B43legacy_STAT_INITIALIZED))) {
++                      err = -ENODEV;
++                      goto out_unlock_mutex;
++              }
++              b43legacy_set_retry_limits(dev,
++                                         conf->short_frame_max_tx_count,
++                                         conf->long_frame_max_tx_count);
++              changed &= ~IEEE80211_CONF_CHANGE_RETRY_LIMITS;
++      }
++
++      if (!changed)
++              goto out_unlock_mutex;
++
+       antenna_tx = B43legacy_ANTENNA_DEFAULT;
+       antenna_rx = B43legacy_ANTENNA_DEFAULT;
+-      mutex_lock(&wl->mutex);
+       dev = wl->current_dev;
+       phy = &dev->phy;
+@@ -2989,20 +3020,6 @@ static void b43legacy_imcfglo_timeouts_w
+ #endif /* CONFIG_SSB_DRIVER_PCICORE */
+ }
+-/* Write the short and long frame retry limit values. */
+-static void b43legacy_set_retry_limits(struct b43legacy_wldev *dev,
+-                                     unsigned int short_retry,
+-                                     unsigned int long_retry)
+-{
+-      /* The retry limit is a 4-bit counter. Enforce this to avoid overflowing
+-       * the chip-internal counter. */
+-      short_retry = min(short_retry, (unsigned int)0xF);
+-      long_retry = min(long_retry, (unsigned int)0xF);
+-
+-      b43legacy_shm_write16(dev, B43legacy_SHM_WIRELESS, 0x0006, short_retry);
+-      b43legacy_shm_write16(dev, B43legacy_SHM_WIRELESS, 0x0007, long_retry);
+-}
+-
+ static void b43legacy_set_synth_pu_delay(struct b43legacy_wldev *dev,
+                                         bool idle) {
+       u16 pu_delay = 1050;
+@@ -3367,28 +3384,6 @@ static void b43legacy_op_stop(struct iee
+       mutex_unlock(&wl->mutex);
+ }
+-static int b43legacy_op_set_retry_limit(struct ieee80211_hw *hw,
+-                                      u32 short_retry_limit,
+-                                      u32 long_retry_limit)
+-{
+-      struct b43legacy_wl *wl = hw_to_b43legacy_wl(hw);
+-      struct b43legacy_wldev *dev;
+-      int err = 0;
+-
+-      mutex_lock(&wl->mutex);
+-      dev = wl->current_dev;
+-      if (unlikely(!dev ||
+-                   (b43legacy_status(dev) < B43legacy_STAT_INITIALIZED))) {
+-              err = -ENODEV;
+-              goto out_unlock;
+-      }
+-      b43legacy_set_retry_limits(dev, short_retry_limit, long_retry_limit);
+-out_unlock:
+-      mutex_unlock(&wl->mutex);
+-
+-      return err;
+-}
+-
+ static int b43legacy_op_beacon_set_tim(struct ieee80211_hw *hw,
+                                      struct ieee80211_sta *sta, bool set)
+ {
+@@ -3414,7 +3409,6 @@ static const struct ieee80211_ops b43leg
+       .get_tx_stats           = b43legacy_op_get_tx_stats,
+       .start                  = b43legacy_op_start,
+       .stop                   = b43legacy_op_stop,
+-      .set_retry_limit        = b43legacy_op_set_retry_limit,
+       .set_tim                = b43legacy_op_beacon_set_tim,
+ };
+--- everything.orig/drivers/net/wireless/rt2x00/rt2400pci.c    2008-10-10 23:27:46.000000000 +0200
++++ everything/drivers/net/wireless/rt2x00/rt2400pci.c 2008-10-10 23:27:48.000000000 +0200
+@@ -1576,7 +1576,6 @@ static const struct ieee80211_ops rt2400
+       .config_interface       = rt2x00mac_config_interface,
+       .configure_filter       = rt2x00mac_configure_filter,
+       .get_stats              = rt2x00mac_get_stats,
+-      .set_retry_limit        = rt2400pci_set_retry_limit,
+       .bss_info_changed       = rt2x00mac_bss_info_changed,
+       .conf_tx                = rt2400pci_conf_tx,
+       .get_tx_stats           = rt2x00mac_get_tx_stats,
+@@ -1605,6 +1604,7 @@ static const struct rt2x00lib_ops rt2400
+       .config_intf            = rt2400pci_config_intf,
+       .config_erp             = rt2400pci_config_erp,
+       .config                 = rt2400pci_config,
++      .set_retry_limit        = rt2400pci_set_retry_limit,
+ };
+ static const struct data_queue_desc rt2400pci_queue_rx = {
+--- everything.orig/drivers/net/wireless/rt2x00/rt2x00.h       2008-10-10 23:27:47.000000000 +0200
++++ everything/drivers/net/wireless/rt2x00/rt2x00.h    2008-10-10 23:27:48.000000000 +0200
+@@ -599,6 +599,9 @@ struct rt2x00lib_ops {
+ #define CONFIG_UPDATE_SLOT_TIME       ( 1 << 5 )
+ #define CONFIG_UPDATE_BEACON_INT      ( 1 << 6 )
+ #define CONFIG_UPDATE_ALL             0xffff
++
++      int (*set_retry_limit) (struct ieee80211_hw *hw,
++                              u32 short_limit, u32 long_limit);
+ };
+ /*
+--- everything.orig/drivers/net/wireless/rt2x00/rt2500pci.c    2008-10-10 23:27:46.000000000 +0200
++++ everything/drivers/net/wireless/rt2x00/rt2500pci.c 2008-10-10 23:27:48.000000000 +0200
+@@ -1877,7 +1877,6 @@ static const struct ieee80211_ops rt2500
+       .config_interface       = rt2x00mac_config_interface,
+       .configure_filter       = rt2x00mac_configure_filter,
+       .get_stats              = rt2x00mac_get_stats,
+-      .set_retry_limit        = rt2500pci_set_retry_limit,
+       .bss_info_changed       = rt2x00mac_bss_info_changed,
+       .conf_tx                = rt2x00mac_conf_tx,
+       .get_tx_stats           = rt2x00mac_get_tx_stats,
+@@ -1906,6 +1905,7 @@ static const struct rt2x00lib_ops rt2500
+       .config_intf            = rt2500pci_config_intf,
+       .config_erp             = rt2500pci_config_erp,
+       .config                 = rt2500pci_config,
++      .set_retry_limit        = rt2500pci_set_retry_limit,
+ };
+ static const struct data_queue_desc rt2500pci_queue_rx = {
+--- everything.orig/drivers/net/wireless/rt2x00/rt61pci.c      2008-10-10 23:27:47.000000000 +0200
++++ everything/drivers/net/wireless/rt2x00/rt61pci.c   2008-10-10 23:27:48.000000000 +0200
+@@ -2726,7 +2726,6 @@ static const struct ieee80211_ops rt61pc
+       .configure_filter       = rt2x00mac_configure_filter,
+       .set_key                = rt2x00mac_set_key,
+       .get_stats              = rt2x00mac_get_stats,
+-      .set_retry_limit        = rt61pci_set_retry_limit,
+       .bss_info_changed       = rt2x00mac_bss_info_changed,
+       .conf_tx                = rt61pci_conf_tx,
+       .get_tx_stats           = rt2x00mac_get_tx_stats,
+@@ -2759,6 +2758,7 @@ static const struct rt2x00lib_ops rt61pc
+       .config_intf            = rt61pci_config_intf,
+       .config_erp             = rt61pci_config_erp,
+       .config                 = rt61pci_config,
++      .set_retry_limit        = rt61pci_set_retry_limit,
+ };
+ static const struct data_queue_desc rt61pci_queue_rx = {
+--- everything.orig/drivers/net/wireless/rt2x00/rt73usb.c      2008-10-10 23:27:47.000000000 +0200
++++ everything/drivers/net/wireless/rt2x00/rt73usb.c   2008-10-10 23:27:48.000000000 +0200
+@@ -2317,7 +2317,6 @@ static const struct ieee80211_ops rt73us
+       .configure_filter       = rt2x00mac_configure_filter,
+       .set_key                = rt2x00mac_set_key,
+       .get_stats              = rt2x00mac_get_stats,
+-      .set_retry_limit        = rt73usb_set_retry_limit,
+       .bss_info_changed       = rt2x00mac_bss_info_changed,
+       .conf_tx                = rt73usb_conf_tx,
+       .get_tx_stats           = rt2x00mac_get_tx_stats,
+@@ -2349,6 +2348,7 @@ static const struct rt2x00lib_ops rt73us
+       .config_intf            = rt73usb_config_intf,
+       .config_erp             = rt73usb_config_erp,
+       .config                 = rt73usb_config,
++      .set_retry_limit        = rt73usb_set_retry_limit,
+ };
+ static const struct data_queue_desc rt73usb_queue_rx = {
+--- everything.orig/drivers/net/wireless/rt2x00/rt2x00mac.c    2008-10-10 23:27:46.000000000 +0200
++++ everything/drivers/net/wireless/rt2x00/rt2x00mac.c 2008-10-10 23:31:23.000000000 +0200
+@@ -349,6 +349,15 @@ int rt2x00mac_config(struct ieee80211_hw
+       if (!test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags))
+               return 0;
++      if (changed & IEEE80211_CONF_CHANGE_RETRY_LIMITS) {
++              rt2x00dev->ops->lib->set_retry_limit(hw,
++                      conf->short_frame_max_tx_count,
++                      conf->long_frame_max_tx_count);
++      }
++      changed &= ~IEEE80211_CONF_CHANGE_RETRY_LIMITS;
++      if (!changed)
++              return 0;
++
+       /*
+        * Only change device state when the radio is enabled. It does not
+        * matter what parameters we have configured when the radio is disabled
+--- everything.orig/net/mac80211/debugfs.c     2008-10-10 23:27:46.000000000 +0200
++++ everything/net/mac80211/debugfs.c  2008-10-10 23:27:48.000000000 +0200
+@@ -52,9 +52,9 @@ DEBUGFS_READONLY_FILE(rts_threshold, 20,
+ DEBUGFS_READONLY_FILE(fragmentation_threshold, 20, "%d",
+                     local->fragmentation_threshold);
+ DEBUGFS_READONLY_FILE(short_retry_limit, 20, "%d",
+-                    local->short_retry_limit);
++                    local->hw.conf.short_frame_max_tx_count);
+ DEBUGFS_READONLY_FILE(long_retry_limit, 20, "%d",
+-                    local->long_retry_limit);
++                    local->hw.conf.long_frame_max_tx_count);
+ DEBUGFS_READONLY_FILE(total_ps_buffered, 20, "%d",
+                     local->total_ps_buffered);
+ DEBUGFS_READONLY_FILE(wep_iv, 20, "%#06x",
+--- everything.orig/net/mac80211/tx.c  2008-10-10 23:27:46.000000000 +0200
++++ everything/net/mac80211/tx.c       2008-10-10 23:31:22.000000000 +0200
+@@ -507,10 +507,10 @@ ieee80211_tx_h_misc(struct ieee80211_tx_
+                               info->flags |=
+                                       IEEE80211_TX_CTL_LONG_RETRY_LIMIT;
+                               info->control.retry_limit =
+-                                      tx->local->long_retry_limit;
++                                      tx->local->hw.conf.long_frame_max_tx_count - 1;
+                       } else {
+                               info->control.retry_limit =
+-                                      tx->local->short_retry_limit;
++                                      tx->local->hw.conf.short_frame_max_tx_count - 1;
+                       }
+               } else {
+                       info->control.retry_limit = 1;
diff --git a/package/mac80211/patches/425-rewrite-rate-api.patch b/package/mac80211/patches/425-rewrite-rate-api.patch
new file mode 100644 (file)
index 0000000..c0652a0
--- /dev/null
@@ -0,0 +1,3005 @@
+Subject: mac80211/drivers: rewrite the rate control API
+
+So after the previous changes we were still unhappy with how
+convoluted the API is and decided to make things simpler for
+everybody. This completely changes the rate control API, now
+taking into account 802.11n with MCS rates and more control,
+most drivers don't support that though.
+
+Signed-off-by: Felix Fietkau <nbd@openwrt.org>
+Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
+---
+ drivers/net/wireless/adm8211.c              |   21 -
+ drivers/net/wireless/ath5k/base.c           |   34 +-
+ drivers/net/wireless/ath9k/main.c           |   18 -
+ drivers/net/wireless/ath9k/rc.c             |   40 +--
+ drivers/net/wireless/ath9k/xmit.c           |   28 +-
+ drivers/net/wireless/b43/dma.c              |    4 
+ drivers/net/wireless/b43/main.c             |    2 
+ drivers/net/wireless/b43/pio.c              |    4 
+ drivers/net/wireless/b43/xmit.c             |   60 +++-
+ drivers/net/wireless/b43/xmit.h             |    5 
+ drivers/net/wireless/b43legacy/dma.c        |   46 ++-
+ drivers/net/wireless/b43legacy/main.c       |    2 
+ drivers/net/wireless/b43legacy/pio.c        |   31 ++
+ drivers/net/wireless/b43legacy/xmit.c       |   26 +-
+ drivers/net/wireless/b43legacy/xmit.h       |    2 
+ drivers/net/wireless/iwlwifi/iwl-3945-rs.c  |   57 +---
+ drivers/net/wireless/iwlwifi/iwl-3945.c     |   62 ++++-
+ drivers/net/wireless/iwlwifi/iwl-3945.h     |    2 
+ drivers/net/wireless/iwlwifi/iwl-4965.c     |    8 
+ drivers/net/wireless/iwlwifi/iwl-5000.c     |    8 
+ drivers/net/wireless/iwlwifi/iwl-agn-rs.c   |   37 +-
+ drivers/net/wireless/iwlwifi/iwl-core.c     |   19 -
+ drivers/net/wireless/iwlwifi/iwl3945-base.c |    5 
+ drivers/net/wireless/libertas_tf/main.c     |    4 
+ drivers/net/wireless/mac80211_hwsim.c       |   12 
+ drivers/net/wireless/p54/p54common.c        |   16 -
+ drivers/net/wireless/rt2x00/rt2x00dev.c     |   11 
+ drivers/net/wireless/rt2x00/rt2x00mac.c     |   14 -
+ drivers/net/wireless/rt2x00/rt2x00queue.c   |   11 
+ drivers/net/wireless/rtl8180_dev.c          |   28 +-
+ drivers/net/wireless/rtl8187_dev.c          |   10 
+ drivers/net/wireless/zd1211rw/zd_mac.c      |   28 +-
+ include/net/mac80211.h                      |  206 +++++++++-------
+ net/mac80211/ieee80211_i.h                  |    8 
+ net/mac80211/main.c                         |   54 +++-
+ net/mac80211/mesh_hwmp.c                    |    6 
+ net/mac80211/rate.c                         |   50 +---
+ net/mac80211/rate.h                         |    5 
+ net/mac80211/rc80211_minstrel.c             |   72 ++---
+ net/mac80211/rc80211_pid.h                  |    1 
+ net/mac80211/rc80211_pid_algo.c             |   26 +-
+ net/mac80211/rc80211_pid_debugfs.c          |    5 
+ net/mac80211/sta_info.h                     |    4 
+ net/mac80211/tx.c                           |  347 +++++++++++-----------------
+ net/mac80211/wext.c                         |    4 
+ 45 files changed, 781 insertions(+), 662 deletions(-)
+
+--- a/include/net/mac80211.h
++++ b/include/net/mac80211.h
+@@ -222,29 +222,24 @@ struct ieee80211_bss_conf {
+  * These flags are used with the @flags member of &ieee80211_tx_info.
+  *
+  * @IEEE80211_TX_CTL_REQ_TX_STATUS: request TX status callback for this frame.
+- * @IEEE80211_TX_CTL_USE_RTS_CTS: use RTS-CTS before sending frame
+- * @IEEE80211_TX_CTL_USE_CTS_PROTECT: use CTS protection for the frame (e.g.,
+- *    for combined 802.11g / 802.11b networks)
++ * @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.
+  * @IEEE80211_TX_CTL_NO_ACK: tell the low level not to wait for an ack
+- * @IEEE80211_TX_CTL_RATE_CTRL_PROBE: TBD
+  * @IEEE80211_TX_CTL_CLEAR_PS_FILT: clear powersave filter for destination
+  *    station
+- * @IEEE80211_TX_CTL_REQUEUE: TBD
+  * @IEEE80211_TX_CTL_FIRST_FRAGMENT: this is a first fragment of the frame
+- * @IEEE80211_TX_CTL_SHORT_PREAMBLE: TBD
+- * @IEEE80211_TX_CTL_LONG_RETRY_LIMIT: this frame should be send using the
+- *    through set_retry_limit configured long retry value
+  * @IEEE80211_TX_CTL_SEND_AFTER_DTIM: send this frame after DTIM beacon
+  * @IEEE80211_TX_CTL_AMPDU: this frame should be sent as part of an A-MPDU
+- * @IEEE80211_TX_CTL_OFDM_HT: this frame can be sent in HT OFDM rates. number
+- *    of streams when this flag is on can be extracted from antenna_sel_tx,
+- *    so if 1 antenna is marked use SISO, 2 antennas marked use MIMO, n
+- *    antennas marked use MIMO_n.
+- * @IEEE80211_TX_CTL_GREEN_FIELD: use green field protection for this frame
+- * @IEEE80211_TX_CTL_40_MHZ_WIDTH: send this frame using 40 Mhz channel width
+- * @IEEE80211_TX_CTL_DUP_DATA: duplicate data frame on both 20 Mhz channels
+- * @IEEE80211_TX_CTL_SHORT_GI: send this frame using short guard interval
+- * @IEEE80211_TX_CTL_INJECTED: TBD
++ * @IEEE80211_TX_CTL_INJECTED: Frame was injected, internal to mac80211.
+  * @IEEE80211_TX_STAT_TX_FILTERED: The frame was not transmitted
+  *    because the destination STA was in powersave mode.
+  * @IEEE80211_TX_STAT_ACK: Frame was acknowledged
+@@ -252,42 +247,41 @@ struct ieee80211_bss_conf {
+  *    is for the whole aggregation.
+  * @IEEE80211_TX_STAT_AMPDU_NO_BACK: no block ack was returned,
+  *    so consider using block ack request (BAR).
+- * @IEEE80211_TX_CTL_ASSIGN_SEQ: The driver has to assign a sequence
+- *    number to this frame, taking care of not overwriting the fragment
+- *    number and increasing the sequence number only when the
+- *    IEEE80211_TX_CTL_FIRST_FRAGMENT flags is set. mac80211 will properly
+- *    assign sequence numbers to QoS-data frames but cannot do so correctly
+- *    for non-QoS-data and management frames because beacons need them from
+- *    that counter as well and mac80211 cannot guarantee proper sequencing.
+- *    If this flag is set, the driver should instruct the hardware to
+- *    assign a sequence number to the frame or assign one itself. Cf. IEEE
+- *    802.11-2007 7.1.3.4.1 paragraph 3. This flag will always be set for
+- *    beacons always be clear for frames without a sequence number field.
++ * @IEEE80211_TX_CTL_RATE_CTRL_PROBE: internal to mac80211, can be
++ *    set by rate control algorithms to indicate probe rate, will
++ *    be cleared for fragmented frames (except on the last fragment)
++ * @IEEE80211_TX_CTL_REQUEUE: REMOVE THIS
+  */
+ enum mac80211_tx_control_flags {
+       IEEE80211_TX_CTL_REQ_TX_STATUS          = BIT(0),
+-      IEEE80211_TX_CTL_USE_RTS_CTS            = BIT(2),
+-      IEEE80211_TX_CTL_USE_CTS_PROTECT        = BIT(3),
+-      IEEE80211_TX_CTL_NO_ACK                 = BIT(4),
+-      IEEE80211_TX_CTL_RATE_CTRL_PROBE        = BIT(5),
+-      IEEE80211_TX_CTL_CLEAR_PS_FILT          = BIT(6),
+-      IEEE80211_TX_CTL_REQUEUE                = BIT(7),
+-      IEEE80211_TX_CTL_FIRST_FRAGMENT         = BIT(8),
+-      IEEE80211_TX_CTL_SHORT_PREAMBLE         = BIT(9),
+-      IEEE80211_TX_CTL_LONG_RETRY_LIMIT       = BIT(10),
+-      IEEE80211_TX_CTL_SEND_AFTER_DTIM        = BIT(12),
+-      IEEE80211_TX_CTL_AMPDU                  = BIT(13),
+-      IEEE80211_TX_CTL_OFDM_HT                = BIT(14),
+-      IEEE80211_TX_CTL_GREEN_FIELD            = BIT(15),
+-      IEEE80211_TX_CTL_40_MHZ_WIDTH           = BIT(16),
+-      IEEE80211_TX_CTL_DUP_DATA               = BIT(17),
+-      IEEE80211_TX_CTL_SHORT_GI               = BIT(18),
+-      IEEE80211_TX_CTL_INJECTED               = BIT(19),
+-      IEEE80211_TX_STAT_TX_FILTERED           = BIT(20),
+-      IEEE80211_TX_STAT_ACK                   = BIT(21),
+-      IEEE80211_TX_STAT_AMPDU                 = BIT(22),
+-      IEEE80211_TX_STAT_AMPDU_NO_BACK         = BIT(23),
+-      IEEE80211_TX_CTL_ASSIGN_SEQ             = BIT(24),
++      IEEE80211_TX_CTL_ASSIGN_SEQ             = BIT(1),
++      IEEE80211_TX_CTL_NO_ACK                 = BIT(2),
++      IEEE80211_TX_CTL_CLEAR_PS_FILT          = BIT(3),
++      IEEE80211_TX_CTL_FIRST_FRAGMENT         = BIT(4),
++      IEEE80211_TX_CTL_SEND_AFTER_DTIM        = BIT(5),
++      IEEE80211_TX_CTL_AMPDU                  = BIT(6),
++      IEEE80211_TX_CTL_INJECTED               = BIT(7),
++      IEEE80211_TX_STAT_TX_FILTERED           = BIT(8),
++      IEEE80211_TX_STAT_ACK                   = BIT(9),
++      IEEE80211_TX_STAT_AMPDU                 = BIT(10),
++      IEEE80211_TX_STAT_AMPDU_NO_BACK         = BIT(11),
++      IEEE80211_TX_CTL_RATE_CTRL_PROBE        = BIT(12),
++
++      /* XXX: remove this */
++      IEEE80211_TX_CTL_REQUEUE                = BIT(13),
++};
++
++enum mac80211_rate_control_flags {
++      IEEE80211_TX_RC_USE_RTS_CTS             = BIT(0),
++      IEEE80211_TX_RC_USE_CTS_PROTECT         = BIT(1),
++      IEEE80211_TX_RC_USE_SHORT_PREAMBLE      = BIT(2),
++
++      /* rate index is an MCS rate number instead of an index */
++      IEEE80211_TX_RC_MCS                     = BIT(3),
++      IEEE80211_TX_RC_GREEN_FIELD             = BIT(4),
++      IEEE80211_TX_RC_40_MHZ_WIDTH            = BIT(5),
++      IEEE80211_TX_RC_DUP_DATA                = BIT(6),
++      IEEE80211_TX_RC_SHORT_GI                = BIT(7),
+ };
+@@ -296,18 +290,26 @@ enum mac80211_tx_control_flags {
+ #define IEEE80211_TX_INFO_DRIVER_DATA_PTRS \
+       (IEEE80211_TX_INFO_DRIVER_DATA_SIZE / sizeof(void *))
+-/* maximum number of alternate rate retry stages */
+-#define IEEE80211_TX_MAX_ALTRATE      3
++/* maximum number of rate stages */
++#define IEEE80211_TX_MAX_RATES        4
+ /**
+- * struct ieee80211_tx_altrate - alternate rate selection/status
++ * struct ieee80211_tx_rate - rate selection/status
+  *
+- * @rate_idx: rate index to attempt to send with
++ * @idx: rate index to attempt to send with
++ * @flags: rate control flags (&enum mac80211_rate_control_flags)
+  * @limit: number of retries before fallback
++ *
++ * A value of -1 for @idx indicates an invalid rate and, if used
++ * in an array of retry rates, that no more rates should be tried.
++ *
++ * When used for transmit status reporting, the driver should
++ * always report the rate along with the flags it used.
+  */
+-struct ieee80211_tx_altrate {
+-      s8 rate_idx;
+-      u8 limit;
++struct ieee80211_tx_rate {
++      s8 idx;
++      u8 count;
++      u8 flags;
+ };
+ /**
+@@ -322,15 +324,12 @@ struct ieee80211_tx_altrate {
+  * it may be NULL.
+  *
+  * @flags: transmit info flags, defined above
+- * @band: TBD
+- * @tx_rate_idx: TBD
++ * @band: the band to transmit on (use for checking for races)
+  * @antenna_sel_tx: antenna to use, 0 for automatic diversity
+  * @control: union for control data
+  * @status: union for status data
+  * @driver_data: array of driver_data pointers
+  * @retry_count: number of retries
+- * @excessive_retries: set to 1 if the frame was retried many times
+- *    but not acknowledged
+  * @ampdu_ack_len: number of aggregated frames.
+  *    relevant only if IEEE80211_TX_STATUS_AMPDU was set.
+  * @ampdu_ack_map: block ack bit map for the aggregation.
+@@ -341,28 +340,28 @@ struct ieee80211_tx_info {
+       /* common information */
+       u32 flags;
+       u8 band;
+-      s8 tx_rate_idx;
++
+       u8 antenna_sel_tx;
+-      /* 1 byte hole */
++      /* 2 byte hole */
+       union {
+               struct {
++                      union {
++                      struct ieee80211_tx_rate rates[IEEE80211_TX_MAX_RATES];
++                      /* we need the jiffies only before rate control */
++                      unsigned long jiffies;
++                      };
++                      s8 rts_cts_rate_idx;
+                       /* NB: vif can be NULL for injected frames */
+                       struct ieee80211_vif *vif;
+                       struct ieee80211_key_conf *hw_key;
+                       struct ieee80211_sta *sta;
+-                      unsigned long jiffies;
+-                      s8 rts_cts_rate_idx;
+-                      u8 retry_limit;
+-                      struct ieee80211_tx_altrate retries[IEEE80211_TX_MAX_ALTRATE];
+               } control;
+               struct {
++                      struct ieee80211_tx_rate rates[IEEE80211_TX_MAX_RATES];
+                       u64 ampdu_ack_map;
+                       int ack_signal;
+-                      struct ieee80211_tx_altrate retries[IEEE80211_TX_MAX_ALTRATE + 1];
+-                      u8 retry_count;
+-                      bool excessive_retries;
+                       u8 ampdu_ack_len;
+               } status;
+               void *driver_data[IEEE80211_TX_INFO_DRIVER_DATA_PTRS];
+@@ -374,6 +373,22 @@ static inline struct ieee80211_tx_info *
+       return (struct ieee80211_tx_info *)skb->cb;
+ }
++static inline void
++ieee80211_tx_info_clear_status(struct ieee80211_tx_info *info)
++{
++      int i;
++
++      BUILD_BUG_ON(offsetof(struct ieee80211_tx_info, status.rates) !=
++                   offsetof(struct ieee80211_tx_info, control.rates));
++      /* clear the rate counts */
++      for (i = 0; i < IEEE80211_TX_MAX_RATES; i++)
++              info->status.rates[i].count = 0;
++
++      memset(&info->status.ampdu_ack_map, 0,
++             sizeof(struct ieee80211_tx_info) -
++             offsetof(struct ieee80211_tx_info, status.ampdu_ack_map));
++}
++
+ /**
+  * enum mac80211_rx_flags - receive flags
+@@ -875,8 +890,8 @@ enum ieee80211_hw_flags {
+  * @sta_data_size: size (in bytes) of the drv_priv data area
+  *    within &struct ieee80211_sta.
+  *
+- * @max_altrates: maximum number of alternate rate retry stages
+- * @max_altrate_tries: maximum number of tries for each stage
++ * @max_rates: maximum number of alternate rate retry stages
++ * @max_rate_tries: maximum number of tries for each stage
+  */
+ struct ieee80211_hw {
+       struct ieee80211_conf conf;
+@@ -893,8 +908,8 @@ struct ieee80211_hw {
+       u16 ampdu_queues;
+       u16 max_listen_interval;
+       s8 max_signal;
+-      u8 max_altrates;
+-      u8 max_altrate_tries;
++      u8 max_rates;
++      u8 max_rate_tries;
+ };
+ /**
+@@ -933,9 +948,9 @@ static inline struct ieee80211_rate *
+ ieee80211_get_tx_rate(const struct ieee80211_hw *hw,
+                     const struct ieee80211_tx_info *c)
+ {
+-      if (WARN_ON(c->tx_rate_idx < 0))
++      if (WARN_ON(c->control.rates[0].idx < 0))
+               return NULL;
+-      return &hw->wiphy->bands[c->band]->bitrates[c->tx_rate_idx];
++      return &hw->wiphy->bands[c->band]->bitrates[c->control.rates[0].idx];
+ }
+ static inline struct ieee80211_rate *
+@@ -951,9 +966,9 @@ static inline struct ieee80211_rate *
+ ieee80211_get_alt_retry_rate(const struct ieee80211_hw *hw,
+                            const struct ieee80211_tx_info *c, int idx)
+ {
+-      if (c->control.retries[idx].rate_idx < 0)
++      if (c->control.rates[idx + 1].idx < 0)
+               return NULL;
+-      return &hw->wiphy->bands[c->band]->bitrates[c->control.retries[idx].rate_idx];
++      return &hw->wiphy->bands[c->band]->bitrates[c->control.rates[idx + 1].idx];
+ }
+ /**
+@@ -1847,17 +1862,28 @@ struct ieee80211_sta *ieee80211_find_sta
+ /* Rate control API */
++
+ /**
+- * struct rate_selection - rate information for/from rate control algorithms
++ * struct ieee80211_tx_rate_control - rate control information for/from RC algo
+  *
+- * @rate_idx: selected transmission rate index
+- * @nonerp_idx: Non-ERP rate to use instead if ERP cannot be used
+- * @probe_idx: rate for probing (or -1)
+- * @max_rate_idx: maximum rate index that can be used, this is
+- *    input to the algorithm and will be enforced
+- */
+-struct rate_selection {
+-      s8 rate_idx, nonerp_idx, probe_idx, max_rate_idx;
++ * @sband: The band this frame is being transmitted on.
++ * @bss_conf: the current BSS configuration
++ * @reported_rate: The rate control algorithm can fill this in to indicate
++ *    which rate should be reported to userspace as the current rate and
++ *    used for rate calculations in the mesh network.
++ * @rts: whether RTS will be used for this frame because it is longer than the
++ *    RTS threshold
++ * @short_preamble: whether mac80211 will request short-preamble transmission
++ *    if the selected rate supports it
++ * @max_rate_idx: user-requested maximum rate (not MCS for now)
++ */
++struct ieee80211_tx_rate_control {
++      struct ieee80211_supported_band *sband;
++      struct ieee80211_bss_conf *bss_conf;
++      struct sk_buff *skb;
++      struct ieee80211_tx_rate reported_rate;
++      bool rts, short_preamble;
++      u8 max_rate_idx;
+ };
+ struct rate_control_ops {
+@@ -1876,10 +1902,8 @@ struct rate_control_ops {
+       void (*tx_status)(void *priv, struct ieee80211_supported_band *sband,
+                         struct ieee80211_sta *sta, void *priv_sta,
+                         struct sk_buff *skb);
+-      void (*get_rate)(void *priv, struct ieee80211_supported_band *sband,
+-                       struct ieee80211_sta *sta, void *priv_sta,
+-                       struct sk_buff *skb,
+-                       struct rate_selection *sel);
++      void (*get_rate)(void *priv, struct ieee80211_sta *sta, void *priv_sta,
++                       struct ieee80211_tx_rate_control *txrc);
+       void (*add_sta_debugfs)(void *priv, void *priv_sta,
+                               struct dentry *dir);
+--- a/net/mac80211/main.c
++++ b/net/mac80211/main.c
+@@ -41,6 +41,8 @@
+  */
+ struct ieee80211_tx_status_rtap_hdr {
+       struct ieee80211_radiotap_header hdr;
++      u8 rate;
++      u8 padding_for_rate;
+       __le16 tx_flags;
+       u8 data_retries;
+ } __attribute__ ((packed));
+@@ -463,13 +465,28 @@ void ieee80211_tx_status(struct ieee8021
+       struct ieee80211_sub_if_data *sdata;
+       struct net_device *prev_dev = NULL;
+       struct sta_info *sta;
++      int retry_count = -1, i;
++
++      for (i = 0; i < IEEE80211_TX_MAX_RATES; i++) {
++              /* the HW cannot have attempted that rate */
++              if (i >= hw->max_rates) {
++                      info->status.rates[i].idx = -1;
++                      info->status.rates[i].count = 0;
++              }
++
++              retry_count += info->status.rates[i].count;
++      }
++      if (retry_count < 0)
++              retry_count = 0;
+       rcu_read_lock();
++      sband = local->hw.wiphy->bands[info->band];
++
+       sta = sta_info_get(local, hdr->addr1);
+       if (sta) {
+-              if (info->status.excessive_retries &&
++              if (!(info->flags & IEEE80211_TX_STAT_ACK) &&
+                   test_sta_flags(sta, WLAN_STA_PS)) {
+                       /*
+                        * The STA is in power save mode, so assume
+@@ -500,12 +517,11 @@ void ieee80211_tx_status(struct ieee8021
+                       rcu_read_unlock();
+                       return;
+               } else {
+-                      if (info->status.excessive_retries)
++                      if (!(info->flags & IEEE80211_TX_STAT_ACK))
+                               sta->tx_retry_failed++;
+-                      sta->tx_retry_count += info->status.retry_count;
++                      sta->tx_retry_count += retry_count;
+               }
+-              sband = local->hw.wiphy->bands[info->band];
+               rate_control_tx_status(local, sband, sta, skb);
+       }
+@@ -526,9 +542,9 @@ void ieee80211_tx_status(struct ieee8021
+                       local->dot11TransmittedFrameCount++;
+                       if (is_multicast_ether_addr(hdr->addr1))
+                               local->dot11MulticastTransmittedFrameCount++;
+-                      if (info->status.retry_count > 0)
++                      if (retry_count > 0)
+                               local->dot11RetryCount++;
+-                      if (info->status.retry_count > 1)
++                      if (retry_count > 1)
+                               local->dot11MultipleRetryCount++;
+               }
+@@ -572,19 +588,30 @@ void ieee80211_tx_status(struct ieee8021
+       rthdr->hdr.it_len = cpu_to_le16(sizeof(*rthdr));
+       rthdr->hdr.it_present =
+               cpu_to_le32((1 << IEEE80211_RADIOTAP_TX_FLAGS) |
+-                          (1 << IEEE80211_RADIOTAP_DATA_RETRIES));
++                          (1 << IEEE80211_RADIOTAP_DATA_RETRIES) |
++                          (1 << IEEE80211_RADIOTAP_RATE));
+       if (!(info->flags & IEEE80211_TX_STAT_ACK) &&
+           !is_multicast_ether_addr(hdr->addr1))
+               rthdr->tx_flags |= cpu_to_le16(IEEE80211_RADIOTAP_F_TX_FAIL);
+-      if ((info->flags & IEEE80211_TX_CTL_USE_RTS_CTS) &&
+-          (info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT))
++      /*
++       * XXX: Once radiotap gets the bitmap reset thing the vendor
++       *      extensions proposal contains, we can actually report
++       *      the whole set of tries we did.
++       */
++      if ((info->status.rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS) ||
++          (info->status.rates[0].flags & IEEE80211_TX_RC_USE_CTS_PROTECT))
+               rthdr->tx_flags |= cpu_to_le16(IEEE80211_RADIOTAP_F_TX_CTS);
+-      else if (info->flags & IEEE80211_TX_CTL_USE_RTS_CTS)
++      else if (info->status.rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS)
+               rthdr->tx_flags |= cpu_to_le16(IEEE80211_RADIOTAP_F_TX_RTS);
++      if (info->status.rates[0].idx >= 0 &&
++          !(info->status.rates[0].flags & IEEE80211_TX_RC_MCS))
++              rthdr->rate = sband->bitrates[
++                              info->status.rates[0].idx].bitrate / 5;
+-      rthdr->data_retries = info->status.retry_count;
++      /* for now report the total retry_count */
++      rthdr->data_retries = retry_count;
+       /* XXX: is this sufficient for BPF? */
+       skb_set_mac_header(skb, 0);
+@@ -669,8 +696,9 @@ struct ieee80211_hw *ieee80211_alloc_hw(
+       BUG_ON(!ops->configure_filter);
+       local->ops = ops;
+-      local->hw.queues = 1; /* default */
+-
++      /* set up some defaults */
++      local->hw.queues = 1;
++      local->hw.max_rates = 1;
+       local->rts_threshold = IEEE80211_MAX_RTS_THRESHOLD;
+       local->fragmentation_threshold = IEEE80211_MAX_FRAG_THRESHOLD;
+       local->hw.conf.long_frame_max_tx_count = 4;
+--- a/net/mac80211/tx.c
++++ b/net/mac80211/tx.c
+@@ -46,13 +46,20 @@ static __le16 ieee80211_duration(struct 
+       struct ieee80211_local *local = tx->local;
+       struct ieee80211_supported_band *sband;
+       struct ieee80211_hdr *hdr;
++      struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx->skb);
++
++      /* assume HW handles this */
++      if (info->control.rates[0].flags & IEEE80211_TX_RC_MCS)
++              return 0;
++
++      /* uh huh? */
++      if (WARN_ON(info->control.rates[0].idx < 0))
++              return 0;
+       sband = local->hw.wiphy->bands[tx->channel->band];
+-      txrate = &sband->bitrates[tx->rate_idx];
++      txrate = &sband->bitrates[info->control.rates[0].idx];
+-      erp = 0;
+-      if (tx->sdata->flags & IEEE80211_SDATA_OPERATING_GMODE)
+-              erp = txrate->flags & IEEE80211_RATE_ERP_G;
++      erp = txrate->flags & IEEE80211_RATE_ERP_G;
+       /*
+        * data and mgmt (except PS Poll):
+@@ -439,140 +446,123 @@ ieee80211_tx_h_select_key(struct ieee802
+ static ieee80211_tx_result debug_noinline
+ ieee80211_tx_h_rate_ctrl(struct ieee80211_tx_data *tx)
+ {
+-      struct rate_selection rsel;
+-      struct ieee80211_supported_band *sband;
+       struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx->skb);
++      struct ieee80211_hdr *hdr = (void *)tx->skb->data;
++      struct ieee80211_supported_band *sband;
++      struct ieee80211_rate *rate;
++      int i, len;
++      bool inval = false, rts = false, short_preamble = false;
++      struct ieee80211_tx_rate_control txrc;
+-      sband = tx->local->hw.wiphy->bands[tx->channel->band];
++      memset(&txrc, 0, sizeof(txrc));
+-      if (likely(tx->rate_idx < 0)) {
+-              rate_control_get_rate(tx->sdata, sband, tx->sta,
+-                                    tx->skb, &rsel);
+-              if (tx->sta)
+-                      tx->sta->last_txrate_idx = rsel.rate_idx;
+-              tx->rate_idx = rsel.rate_idx;
+-              if (unlikely(rsel.probe_idx >= 0)) {
+-                      info->flags |= IEEE80211_TX_CTL_RATE_CTRL_PROBE;
+-                      tx->flags |= IEEE80211_TX_PROBE_LAST_FRAG;
+-                      info->control.retries[0].rate_idx = tx->rate_idx;
+-                      info->control.retries[0].limit = tx->local->hw.max_altrate_tries;
+-                      tx->rate_idx = rsel.probe_idx;
+-              } else if (info->control.retries[0].limit == 0)
+-                      info->control.retries[0].rate_idx = -1;
++      sband = tx->local->hw.wiphy->bands[tx->channel->band];
+-              if (unlikely(tx->rate_idx < 0))
+-                      return TX_DROP;
+-      } else
+-              info->control.retries[0].rate_idx = -1;
++      len = min_t(int, tx->skb->len + FCS_LEN,
++                       tx->local->fragmentation_threshold);
+-      if (tx->sdata->vif.bss_conf.use_cts_prot &&
+-          (tx->flags & IEEE80211_TX_FRAGMENTED) && (rsel.nonerp_idx >= 0)) {
+-              tx->last_frag_rate_idx = tx->rate_idx;
+-              if (rsel.probe_idx >= 0)
+-                      tx->flags &= ~IEEE80211_TX_PROBE_LAST_FRAG;
+-              else
+-                      tx->flags |= IEEE80211_TX_PROBE_LAST_FRAG;
+-              tx->rate_idx = rsel.nonerp_idx;
+-              info->tx_rate_idx = rsel.nonerp_idx;
+-              info->flags &= ~IEEE80211_TX_CTL_RATE_CTRL_PROBE;
+-      } else {
+-              tx->last_frag_rate_idx = tx->rate_idx;
+-              info->tx_rate_idx = tx->rate_idx;
++      /* set up the tx rate control struct we give the RC algo */
++      txrc.sband = sband;
++      txrc.bss_conf = &tx->sdata->vif.bss_conf;
++      txrc.skb = tx->skb;
++      txrc.reported_rate.idx = -1;
++      txrc.max_rate_idx = tx->sdata->max_ratectrl_rateidx;
++
++      /* set up RTS protection if desired */
++      if (tx->local->rts_threshold < IEEE80211_MAX_RTS_THRESHOLD &&
++          len > tx->local->rts_threshold) {
++              txrc.rts = rts = true;
+       }
+-      info->tx_rate_idx = tx->rate_idx;
+-      return TX_CONTINUE;
+-}
++      /* XXX: Is this really the right thing to check? */
++      if (ieee80211_is_data(hdr->frame_control) &&
++          tx->sdata->vif.bss_conf.use_short_preamble &&
++          (!tx->sta || test_sta_flags(tx->sta, WLAN_STA_SHORT_PREAMBLE)))
++              txrc.short_preamble = short_preamble = true;
+-static ieee80211_tx_result debug_noinline
+-ieee80211_tx_h_misc(struct ieee80211_tx_data *tx)
+-{
+-      struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)tx->skb->data;
+-      struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx->skb);
+-      struct ieee80211_supported_band *sband;
+-      sband = tx->local->hw.wiphy->bands[tx->channel->band];
++      rate_control_get_rate(tx->sdata, tx->sta, &txrc);
++
++      if (unlikely(info->control.rates[0].idx < 0))
++              return TX_DROP;
++
++      if (txrc.reported_rate.idx < 0)
++              txrc.reported_rate = info->control.rates[0];
+       if (tx->sta)
+-              info->control.sta = &tx->sta->sta;
++              tx->sta->last_tx_rate = txrc.reported_rate;
+-      if (!info->control.retry_limit) {
+-              if (!is_multicast_ether_addr(hdr->addr1)) {
+-                      int len = min_t(int, tx->skb->len + FCS_LEN,
+-                                      tx->local->fragmentation_threshold);
+-                      if (len > tx->local->rts_threshold
+-                          && tx->local->rts_threshold <
+-                                              IEEE80211_MAX_RTS_THRESHOLD) {
+-                              info->flags |= IEEE80211_TX_CTL_USE_RTS_CTS;
+-                              info->flags |=
+-                                      IEEE80211_TX_CTL_LONG_RETRY_LIMIT;
+-                              info->control.retry_limit =
+-                                      tx->local->hw.conf.long_frame_max_tx_count - 1;
+-                      } else {
+-                              info->control.retry_limit =
+-                                      tx->local->hw.conf.short_frame_max_tx_count - 1;
+-                      }
+-              } else {
+-                      info->control.retry_limit = 1;
+-              }
+-      }
++      if (unlikely(!info->control.rates[0].count))
++              info->control.rates[0].count = 1;
+-      if (tx->flags & IEEE80211_TX_FRAGMENTED) {
+-              /* Do not use multiple retry rates when sending fragmented
+-               * frames.
+-               * TODO: The last fragment could still use multiple retry
+-               * rates. */
+-              info->control.retries[0].rate_idx = -1;
+-      }
+-
+-      /* Use CTS protection for unicast frames sent using extended rates if
+-       * there are associated non-ERP stations and RTS/CTS is not configured
+-       * for the frame. */
+-      if ((tx->sdata->flags & IEEE80211_SDATA_OPERATING_GMODE) &&
+-          (sband->bitrates[tx->rate_idx].flags & IEEE80211_RATE_ERP_G) &&
+-          (tx->flags & IEEE80211_TX_UNICAST) &&
+-          tx->sdata->vif.bss_conf.use_cts_prot &&
+-          !(info->flags & IEEE80211_TX_CTL_USE_RTS_CTS))
+-              info->flags |= IEEE80211_TX_CTL_USE_CTS_PROTECT;
+-
+-      /* Transmit data frames using short preambles if the driver supports
+-       * short preambles at the selected rate and short preambles are
+-       * available on the network at the current point in time. */
+-      if (ieee80211_is_data(hdr->frame_control) &&
+-          (sband->bitrates[tx->rate_idx].flags & IEEE80211_RATE_SHORT_PREAMBLE) &&
+-          tx->sdata->vif.bss_conf.use_short_preamble &&
+-          (!tx->sta || test_sta_flags(tx->sta, WLAN_STA_SHORT_PREAMBLE))) {
+-              info->flags |= IEEE80211_TX_CTL_SHORT_PREAMBLE;
++      if (is_multicast_ether_addr(hdr->addr1)) {
++              /*
++               * XXX: verify the rate is in the basic rateset
++               */
++              return TX_CONTINUE;
+       }
+-      if ((info->flags & IEEE80211_TX_CTL_USE_RTS_CTS) ||
+-          (info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT)) {
+-              struct ieee80211_rate *rate;
+-              s8 baserate = -1;
+-              int idx;
++      for (i = 0; i < IEEE80211_TX_MAX_RATES; i++) {
++              /*
++               * make sure there's no valid rate following
++               * an invalid one, just in case drivers don't
++               * take the API seriously to stop at -1.
++               */
++              if (inval) {
++                      info->control.rates[i].idx = -1;
++                      continue;
++              }
++              if (info->control.rates[i].idx < 0) {
++                      inval = true;
++                      continue;
++              }
+-              /* Do not use multiple retry rates when using RTS/CTS */
+-              info->control.retries[0].rate_idx = -1;
++              /*
++               * For now assume MCS is already set up correctly, this
++               * needs to be fixed.
++               */
++              if (info->control.rates[i].flags & IEEE80211_TX_RC_MCS) {
++                      WARN_ON(info->control.rates[i].idx > 76);
++                      continue;
++              }
+-              /* Use min(data rate, max base rate) as CTS/RTS rate */
+-              rate = &sband->bitrates[tx->rate_idx];
++              /* set up RTS protection if desired */
++              if (rts) {
++                      info->control.rates[i].flags |=
++                              IEEE80211_TX_RC_USE_RTS_CTS;
++                      rts = true;
++              }
+-              for (idx = 0; idx < sband->n_bitrates; idx++) {
+-                      if (sband->bitrates[idx].bitrate > rate->bitrate)
+-                              continue;
+-                      if (tx->sdata->vif.bss_conf.basic_rates & BIT(idx) &&
+-                          (baserate < 0 ||
+-                           (sband->bitrates[baserate].bitrate
+-                            < sband->bitrates[idx].bitrate)))
+-                              baserate = idx;
++              /* RC is busted */
++              if (WARN_ON(info->control.rates[i].idx >=
++                          sband->n_bitrates)) {
++                      info->control.rates[i].idx = -1;
++                      continue;
+               }
+-              if (baserate >= 0)
+-                      info->control.rts_cts_rate_idx = baserate;
+-              else
+-                      info->control.rts_cts_rate_idx = 0;
++              rate = &sband->bitrates[info->control.rates[i].idx];
++
++              /* set up short preamble */
++              if (short_preamble &&
++                  rate->flags & IEEE80211_RATE_SHORT_PREAMBLE)
++                      info->control.rates[i].flags |=
++                              IEEE80211_TX_RC_USE_SHORT_PREAMBLE;
++
++              /* set up G protection */
++              if (!rts && tx->sdata->vif.bss_conf.use_cts_prot &&
++                  rate->flags & IEEE80211_RATE_ERP_G)
++                      info->control.rates[i].flags |=
++                              IEEE80211_TX_RC_USE_CTS_PROTECT;
+       }
++      return TX_CONTINUE;
++}
++
++static ieee80211_tx_result debug_noinline
++ieee80211_tx_h_misc(struct ieee80211_tx_data *tx)
++{
++      struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx->skb);
++
+       if (tx->sta)
+               info->control.sta = &tx->sta->sta;
+@@ -680,6 +670,7 @@ ieee80211_tx_h_fragment(struct ieee80211
+       left = payload_len - per_fragm;
+       for (i = 0; i < num_fragm - 1; i++) {
+               struct ieee80211_hdr *fhdr;
++              struct ieee80211_tx_info *info;
+               size_t copylen;
+               if (left <= 0)
+@@ -694,20 +685,44 @@ ieee80211_tx_h_fragment(struct ieee80211
+                                     IEEE80211_ENCRYPT_TAILROOM);
+               if (!frag)
+                       goto fail;
++
+               /* Make sure that all fragments use the same priority so
+                * that they end up using the same TX queue */
+               frag->priority = first->priority;
++
+               skb_reserve(frag, tx->local->tx_headroom +
+                                 IEEE80211_ENCRYPT_HEADROOM);
++
++              /* copy TX information */
++              info = IEEE80211_SKB_CB(frag);
++              memcpy(info, first->cb, sizeof(frag->cb));
++
++              /* copy/fill in 802.11 header */
+               fhdr = (struct ieee80211_hdr *) skb_put(frag, hdrlen);
+               memcpy(fhdr, first->data, hdrlen);
+-              if (i == num_fragm - 2)
+-                      fhdr->frame_control &= cpu_to_le16(~IEEE80211_FCTL_MOREFRAGS);
+               fhdr->seq_ctrl = cpu_to_le16(seq | ((i + 1) & IEEE80211_SCTL_FRAG));
++
++              if (i == num_fragm - 2) {
++                      /* clear MOREFRAGS bit for the last fragment */
++                      fhdr->frame_control &= cpu_to_le16(~IEEE80211_FCTL_MOREFRAGS);
++              } else {
++                      /*
++                       * No multi-rate retries for fragmented frames, that
++                       * would completely throw off the NAV at other STAs.
++                       */
++                      info->control.rates[1].idx = -1;
++                      info->control.rates[2].idx = -1;
++                      info->control.rates[3].idx = -1;
++                      BUILD_BUG_ON(IEEE80211_TX_MAX_RATES != 4);
++                      info->flags &= ~IEEE80211_TX_CTL_RATE_CTRL_PROBE;
++              }
++
++              /* copy data */
+               copylen = left > per_fragm ? per_fragm : left;
+               memcpy(skb_put(frag, copylen), pos, copylen);
+-              memcpy(frag->cb, first->cb, sizeof(frag->cb));
++
+               skb_copy_queue_mapping(frag, first);
++
+               frag->do_not_encrypt = first->do_not_encrypt;
+               pos += copylen;
+@@ -767,12 +782,10 @@ ieee80211_tx_h_calculate_duration(struct
+                                             tx->extra_frag[0]->len);
+       for (i = 0; i < tx->num_extra_frag; i++) {
+-              if (i + 1 < tx->num_extra_frag) {
++              if (i + 1 < tx->num_extra_frag)
+                       next_len = tx->extra_frag[i + 1]->len;
+-              } else {
++              else
+                       next_len = 0;
+-                      tx->rate_idx = tx->last_frag_rate_idx;
+-              }
+               hdr = (struct ieee80211_hdr *)tx->extra_frag[i]->data;
+               hdr->duration_id = ieee80211_duration(tx, 0, next_len);
+@@ -825,7 +838,6 @@ __ieee80211_parse_tx_radiotap(struct iee
+               (struct ieee80211_radiotap_header *) skb->data;
+       struct ieee80211_supported_band *sband;
+       int ret = ieee80211_radiotap_iterator_init(&iterator, rthdr, skb->len);
+-      struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+       sband = tx->local->hw.wiphy->bands[tx->channel->band];
+@@ -839,8 +851,6 @@ __ieee80211_parse_tx_radiotap(struct iee
+        */
+       while (!ret) {
+-              int i, target_rate;
+-
+               ret = ieee80211_radiotap_iterator_next(&iterator);
+               if (ret)
+@@ -854,38 +864,6 @@ __ieee80211_parse_tx_radiotap(struct iee
+                * get_unaligned((type *)iterator.this_arg) to dereference
+                * iterator.this_arg for type "type" safely on all arches.
+               */
+-              case IEEE80211_RADIOTAP_RATE:
+-                      /*
+-                       * radiotap rate u8 is in 500kbps units eg, 0x02=1Mbps
+-                       * ieee80211 rate int is in 100kbps units eg, 0x0a=1Mbps
+-                       */
+-                      target_rate = (*iterator.this_arg) * 5;
+-                      for (i = 0; i < sband->n_bitrates; i++) {
+-                              struct ieee80211_rate *r;
+-
+-                              r = &sband->bitrates[i];
+-
+-                              if (r->bitrate == target_rate) {
+-                                      tx->rate_idx = i;
+-                                      break;
+-                              }
+-                      }
+-                      break;
+-
+-              case IEEE80211_RADIOTAP_ANTENNA:
+-                      /*
+-                       * radiotap uses 0 for 1st ant, mac80211 is 1 for
+-                       * 1st ant
+-                       */
+-                      info->antenna_sel_tx = (*iterator.this_arg) + 1;
+-                      break;
+-
+-#if 0
+-              case IEEE80211_RADIOTAP_DBM_TX_POWER:
+-                      control->power_level = *iterator.this_arg;
+-                      break;
+-#endif
+-
+               case IEEE80211_RADIOTAP_FLAGS:
+                       if (*iterator.this_arg & IEEE80211_RADIOTAP_F_FCS) {
+                               /*
+@@ -951,8 +929,6 @@ __ieee80211_tx_prepare(struct ieee80211_
+       tx->local = local;
+       tx->sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+       tx->channel = local->hw.conf.channel;
+-      tx->rate_idx = -1;
+-      tx->last_frag_rate_idx = -1;
+       /*
+        * Set this flag (used below to indicate "automatic fragmentation"),
+        * it will be cleared/left by radiotap as desired.
+@@ -1053,23 +1029,11 @@ static int __ieee80211_tx(struct ieee802
+                       if (!tx->extra_frag[i])
+                               continue;
+                       info = IEEE80211_SKB_CB(tx->extra_frag[i]);
+-                      info->flags &= ~(IEEE80211_TX_CTL_USE_RTS_CTS |
+-                                       IEEE80211_TX_CTL_USE_CTS_PROTECT |
+-                                       IEEE80211_TX_CTL_CLEAR_PS_FILT |
++                      info->flags &= ~(IEEE80211_TX_CTL_CLEAR_PS_FILT |
+                                        IEEE80211_TX_CTL_FIRST_FRAGMENT);
+                       if (netif_subqueue_stopped(local->mdev,
+                                                  tx->extra_frag[i]))
+                               return IEEE80211_TX_FRAG_AGAIN;
+-                      if (i == tx->num_extra_frag) {
+-                              info->tx_rate_idx = tx->last_frag_rate_idx;
+-
+-                              if (tx->flags & IEEE80211_TX_PROBE_LAST_FRAG)
+-                                      info->flags |=
+-                                              IEEE80211_TX_CTL_RATE_CTRL_PROBE;
+-                              else
+-                                      info->flags &=
+-                                              ~IEEE80211_TX_CTL_RATE_CTRL_PROBE;
+-                      }
+                       ret = local->ops->tx(local_to_hw(local),
+                                           tx->extra_frag[i]);
+@@ -1206,9 +1170,6 @@ retry:
+               store->skb = skb;
+               store->extra_frag = tx.extra_frag;
+               store->num_extra_frag = tx.num_extra_frag;
+-              store->last_frag_rate_idx = tx.last_frag_rate_idx;
+-              store->last_frag_rate_ctrl_probe =
+-                      !!(tx.flags & IEEE80211_TX_PROBE_LAST_FRAG);
+       }
+  out:
+       rcu_read_unlock();
+@@ -1767,10 +1728,7 @@ void ieee80211_tx_pending(unsigned long 
+               store = &local->pending_packet[i];
+               tx.extra_frag = store->extra_frag;
+               tx.num_extra_frag = store->num_extra_frag;
+-              tx.last_frag_rate_idx = store->last_frag_rate_idx;
+               tx.flags = 0;
+-              if (store->last_frag_rate_ctrl_probe)
+-                      tx.flags |= IEEE80211_TX_PROBE_LAST_FRAG;
+               ret = __ieee80211_tx(local, store->skb, &tx);
+               if (ret) {
+                       if (ret == IEEE80211_TX_FRAG_AGAIN)
+@@ -1858,7 +1816,6 @@ struct sk_buff *ieee80211_beacon_get(str
+       struct ieee80211_sub_if_data *sdata = NULL;
+       struct ieee80211_if_ap *ap = NULL;
+       struct ieee80211_if_sta *ifsta = NULL;
+-      struct rate_selection rsel;
+       struct beacon_data *beacon;
+       struct ieee80211_supported_band *sband;
+       enum ieee80211_band band = local->hw.conf.channel->band;
+@@ -1962,32 +1919,22 @@ struct sk_buff *ieee80211_beacon_get(str
+       skb->do_not_encrypt = 1;
+       info->band = band;
+-      rate_control_get_rate(sdata, sband, NULL, skb, &rsel);
+-
+-      if (unlikely(rsel.rate_idx < 0)) {
+-              if (net_ratelimit()) {
+-                      printk(KERN_DEBUG "%s: ieee80211_beacon_get: "
+-                             "no rate found\n",
+-                             wiphy_name(local->hw.wiphy));
+-              }
+-              dev_kfree_skb_any(skb);
+-              skb = NULL;
+-              goto out;
+-      }
++      /*
++       * XXX: For now, always use the lowest rate
++       */
++      info->control.rates[0].idx = 0;
++      info->control.rates[0].count = 1;
++      info->control.rates[1].idx = -1;
++      info->control.rates[2].idx = -1;
++      info->control.rates[3].idx = -1;
++      BUILD_BUG_ON(IEEE80211_TX_MAX_RATES != 4);
+       info->control.vif = vif;
+-      info->tx_rate_idx = rsel.rate_idx;
+       info->flags |= IEEE80211_TX_CTL_NO_ACK;
+       info->flags |= IEEE80211_TX_CTL_CLEAR_PS_FILT;
+       info->flags |= IEEE80211_TX_CTL_ASSIGN_SEQ;
+-      if (sdata->vif.bss_conf.use_short_preamble &&
+-          sband->bitrates[rsel.rate_idx].flags & IEEE80211_RATE_SHORT_PREAMBLE)
+-              info->flags |= IEEE80211_TX_CTL_SHORT_PREAMBLE;
+-
+-      info->control.retry_limit = 1;
+-
+-out:
++ out:
+       rcu_read_unlock();
+       return skb;
+ }
+--- a/net/mac80211/ieee80211_i.h
++++ b/net/mac80211/ieee80211_i.h
+@@ -142,7 +142,6 @@ typedef unsigned __bitwise__ ieee80211_t
+ #define IEEE80211_TX_FRAGMENTED               BIT(0)
+ #define IEEE80211_TX_UNICAST          BIT(1)
+ #define IEEE80211_TX_PS_BUFFERED      BIT(2)
+-#define IEEE80211_TX_PROBE_LAST_FRAG  BIT(3)
+ struct ieee80211_tx_data {
+       struct sk_buff *skb;
+@@ -153,11 +152,6 @@ struct ieee80211_tx_data {
+       struct ieee80211_key *key;
+       struct ieee80211_channel *channel;
+-      s8 rate_idx;
+-      /* use this rate (if set) for last fragment; rate can
+-       * be set to lower rate for the first fragments, e.g.,
+-       * when using CTS protection with IEEE 802.11g. */
+-      s8 last_frag_rate_idx;
+       /* Extra fragments (in addition to the first fragment
+        * in skb) */
+@@ -203,9 +197,7 @@ struct ieee80211_rx_data {
+ struct ieee80211_tx_stored_packet {
+       struct sk_buff *skb;
+       struct sk_buff **extra_frag;
+-      s8 last_frag_rate_idx;
+       int num_extra_frag;
+-      bool last_frag_rate_ctrl_probe;
+ };
+ struct beacon_data {
+--- a/net/mac80211/rate.c
++++ b/net/mac80211/rate.c
+@@ -199,48 +199,44 @@ static void rate_control_release(struct 
+ }
+ void rate_control_get_rate(struct ieee80211_sub_if_data *sdata,
+-                         struct ieee80211_supported_band *sband,
+-                         struct sta_info *sta, struct sk_buff *skb,
+-                         struct rate_selection *sel)
++                         struct sta_info *sta,
++                         struct ieee80211_tx_rate_control *txrc)
+ {
+       struct rate_control_ref *ref = sdata->local->rate_ctrl;
+       void *priv_sta = NULL;
+       struct ieee80211_sta *ista = NULL;
++      struct ieee80211_tx_info *info = IEEE80211_SKB_CB(txrc->skb);
+       int i;
+-      sel->rate_idx = -1;
+-      sel->nonerp_idx = -1;
+-      sel->probe_idx = -1;
+-      sel->max_rate_idx = sdata->max_ratectrl_rateidx;
+-
+       if (sta) {
+               ista = &sta->sta;
+               priv_sta = sta->rate_ctrl_priv;
+       }
++      for (i = 0; i < IEEE80211_TX_MAX_RATES; i++) {
++              info->control.rates[i].idx = -1;
++              info->control.rates[i].flags = 0;
++              info->control.rates[i].count = 1;
++      }
++
+       if (sta && sdata->force_unicast_rateidx > -1)
+-              sel->rate_idx = sdata->force_unicast_rateidx;
++              info->control.rates[0].idx = sdata->force_unicast_rateidx;
+       else
+-              ref->ops->get_rate(ref->priv, sband, ista, priv_sta, skb, sel);
++              ref->ops->get_rate(ref->priv, ista, priv_sta, txrc);
+-      if (sdata->max_ratectrl_rateidx > -1 &&
+-          sel->rate_idx > sdata->max_ratectrl_rateidx)
+-              sel->rate_idx = sdata->max_ratectrl_rateidx;
+-
+-      BUG_ON(sel->rate_idx < 0);
+-
+-      /* Select a non-ERP backup rate. */
+-      if (sel->nonerp_idx < 0) {
+-              for (i = 0; i < sband->n_bitrates; i++) {
+-                      struct ieee80211_rate *rate = &sband->bitrates[i];
+-                      if (sband->bitrates[sel->rate_idx].bitrate < rate->bitrate)
+-                              break;
+-
+-                      if (rate_supported(ista, sband->band, i) &&
+-                          !(rate->flags & IEEE80211_RATE_ERP_G))
+-                              sel->nonerp_idx = i;
+-              }
++      /*
++       * try to enforce the maximum rate the user wanted
++       */
++      if (sdata->max_ratectrl_rateidx > -1)
++              for (i = 0; i < IEEE80211_TX_MAX_RATES; i++) {
++                      if (info->control.rates[i].flags & IEEE80211_TX_RC_MCS)
++                              continue;
++                      info->control.rates[i].idx =
++                              min_t(s8, info->control.rates[i].idx,
++                                    sdata->max_ratectrl_rateidx);
+       }
++
++      BUG_ON(info->control.rates[0].idx < 0);
+ }
+ struct rate_control_ref *rate_control_get(struct rate_control_ref *ref)
+--- a/net/mac80211/rate.h
++++ b/net/mac80211/rate.h
+@@ -31,9 +31,8 @@ struct rate_control_ref {
+ struct rate_control_ref *rate_control_alloc(const char *name,
+                                           struct ieee80211_local *local);
+ void rate_control_get_rate(struct ieee80211_sub_if_data *sdata,
+-                         struct ieee80211_supported_band *sband,
+-                         struct sta_info *sta, struct sk_buff *skb,
+-                         struct rate_selection *sel);
++                         struct sta_info *sta,
++                         struct ieee80211_tx_rate_control *txrc);
+ struct rate_control_ref *rate_control_get(struct rate_control_ref *ref);
+ void rate_control_put(struct rate_control_ref *ref);
+--- a/net/mac80211/sta_info.h
++++ b/net/mac80211/sta_info.h
+@@ -196,7 +196,7 @@ struct sta_ampdu_mlme {
+  * @tx_packets: number of RX/TX MSDUs
+  * @tx_bytes: TBD
+  * @tx_fragments: number of transmitted MPDUs
+- * @last_txrate_idx: Index of the last used transmit rate
++ * @last_txrate: description of the last used transmit rate
+  * @tid_seq: TBD
+  * @ampdu_mlme: TBD
+  * @timer_to_tid: identity mapping to ID timers
+@@ -267,7 +267,7 @@ struct sta_info {
+       unsigned long tx_packets;
+       unsigned long tx_bytes;
+       unsigned long tx_fragments;
+-      unsigned int last_txrate_idx;
++      struct ieee80211_tx_rate last_tx_rate;
+       u16 tid_seq[IEEE80211_QOS_CTL_TID_MASK + 1];
+       /*
+--- a/net/mac80211/wext.c
++++ b/net/mac80211/wext.c
+@@ -636,8 +636,8 @@ static int ieee80211_ioctl_giwrate(struc
+       sta = sta_info_get(local, sdata->u.sta.bssid);
+-      if (sta && sta->last_txrate_idx < sband->n_bitrates)
+-              rate->value = sband->bitrates[sta->last_txrate_idx].bitrate;
++      if (sta && !(sta->last_tx_rate.flags & IEEE80211_TX_RC_MCS))
++              rate->value = sband->bitrates[sta->last_tx_rate.idx].bitrate;
+       else
+               rate->value = 0;
+--- a/net/mac80211/mesh_hwmp.c
++++ b/net/mac80211/mesh_hwmp.c
+@@ -218,12 +218,16 @@ static u32 airtime_link_metric_get(struc
+       if (sta->fail_avg >= 100)
+               return MAX_METRIC;
++
++      if (sta->last_tx_rate.flags & IEEE80211_TX_RC_MCS)
++              return MAX_METRIC;
++
+       err = (sta->fail_avg << ARITH_SHIFT) / 100;
+       /* bitrate is in units of 100 Kbps, while we need rate in units of
+        * 1Mbps. This will be corrected on tx_time computation.
+        */
+-      rate = sband->bitrates[sta->last_txrate_idx].bitrate;
++      rate = sband->bitrates[sta->last_tx_rate.idx].bitrate;
+       tx_time = (device_constant + 10 * test_frame_len / rate);
+       estimated_retx = ((1 << (2 * ARITH_SHIFT)) / (s_unit - err));
+       result = (tx_time * estimated_retx) >> (2 * ARITH_SHIFT) ;
+--- a/net/mac80211/rc80211_pid_algo.c
++++ b/net/mac80211/rc80211_pid_algo.c
+@@ -241,7 +241,7 @@ static void rate_control_pid_tx_status(v
+       /* Ignore all frames that were sent with a different rate than the rate
+        * we currently advise mac80211 to use. */
+-      if (info->tx_rate_idx != spinfo->txrate_idx)
++      if (info->status.rates[0].idx != spinfo->txrate_idx)
+               return;
+       spinfo->tx_num_xmit++;
+@@ -253,10 +253,10 @@ static void rate_control_pid_tx_status(v
+       /* We count frames that totally failed to be transmitted as two bad
+        * frames, those that made it out but had some retries as one good and
+        * one bad frame. */
+-      if (info->status.excessive_retries) {
++      if (!(info->flags & IEEE80211_TX_STAT_ACK)) {
+               spinfo->tx_num_failed += 2;
+               spinfo->tx_num_xmit++;
+-      } else if (info->status.retry_count) {
++      } else if (info->status.rates[0].count) {
+               spinfo->tx_num_failed++;
+               spinfo->tx_num_xmit++;
+       }
+@@ -270,23 +270,31 @@ static void rate_control_pid_tx_status(v
+ }
+ static void
+-rate_control_pid_get_rate(void *priv, struct ieee80211_supported_band *sband,
+-                        struct ieee80211_sta *sta, void *priv_sta,
+-                        struct sk_buff *skb,
+-                        struct rate_selection *sel)
++rate_control_pid_get_rate(void *priv, struct ieee80211_sta *sta,
++                        void *priv_sta,
++                        struct ieee80211_tx_rate_control *txrc)
+ {
++      struct sk_buff *skb = txrc->skb;
++      struct ieee80211_supported_band *sband = txrc->sband;
+       struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
++      struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+       struct rc_pid_sta_info *spinfo = priv_sta;
+       int rateidx;
+       u16 fc;
++      /* XXX: Should use the user-configured values */
++      if (txrc->rts)
++              info->control.rates[0].count = 4; /* long retry count */
++      else
++              info->control.rates[0].count = 7; /* short retry count */
++
+       /* Send management frames and broadcast/multicast data using lowest
+        * rate. */
+       fc = le16_to_cpu(hdr->frame_control);
+       if (!sta || !spinfo ||
+           (fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA ||
+           is_multicast_ether_addr(hdr->addr1)) {
+-              sel->rate_idx = rate_lowest_index(sband, sta);
++              info->control.rates[0].idx = rate_lowest_index(sband, sta);
+               return;
+       }
+@@ -295,7 +303,7 @@ rate_control_pid_get_rate(void *priv, st
+       if (rateidx >= sband->n_bitrates)
+               rateidx = sband->n_bitrates - 1;
+-      sel->rate_idx = rateidx;
++      info->control.rates[0].idx = rateidx;
+ #ifdef CONFIG_MAC80211_DEBUGFS
+       rate_control_pid_event_tx_rate(&spinfo->events,
+--- a/net/mac80211/rc80211_minstrel.c
++++ b/net/mac80211/rc80211_minstrel.c
+@@ -169,30 +169,20 @@ minstrel_tx_status(void *priv, struct ie
+ {
+       struct minstrel_sta_info *mi = priv_sta;
+       struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+-      struct ieee80211_tx_altrate *ar = info->status.retries;
+-      struct minstrel_priv *mp = priv;
+-      int i, ndx, tries;
+-      int success = 0;
++      struct ieee80211_tx_rate *ar = info->status.rates;
++      int i, ndx;
++      int success;
+-      if (!info->status.excessive_retries)
+-              success = 1;
++      success = !!(info->flags & IEEE80211_TX_STAT_ACK);
+-      if (!mp->has_mrr || (ar[0].rate_idx < 0)) {
+-              ndx = rix_to_ndx(mi, info->tx_rate_idx);
+-              tries = info->status.retry_count + 1;
+-              mi->r[ndx].success += success;
+-              mi->r[ndx].attempts += tries;
+-              return;
+-      }
+-
+-      for (i = 0; i < 4; i++) {
+-              if (ar[i].rate_idx < 0)
++      for (i = 0; i < IEEE80211_TX_MAX_RATES; i++) {
++              if (ar[i].idx < 0)
+                       break;
+-              ndx = rix_to_ndx(mi, ar[i].rate_idx);
+-              mi->r[ndx].attempts += ar[i].limit + 1;
++              ndx = rix_to_ndx(mi, ar[i].idx);
++              mi->r[ndx].attempts += ar[i].count;
+-              if ((i != 3) && (ar[i + 1].rate_idx < 0))
++              if ((i != IEEE80211_TX_MAX_RATES - 1) && (ar[i + 1].idx < 0))
+                       mi->r[ndx].success += success;
+       }
+@@ -210,9 +200,9 @@ minstrel_get_retry_count(struct minstrel
+ {
+       unsigned int retry = mr->adjusted_retry_count;
+-      if (info->flags & IEEE80211_TX_CTL_USE_RTS_CTS)
++      if (info->control.rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS)
+               retry = max(2U, min(mr->retry_count_rtscts, retry));
+-      else if (info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT)
++      else if (info->control.rates[0].flags & IEEE80211_TX_RC_USE_CTS_PROTECT)
+               retry = max(2U, min(mr->retry_count_cts, retry));
+       return retry;
+ }
+@@ -234,14 +224,15 @@ minstrel_get_next_sample(struct minstrel
+ }
+ void
+-minstrel_get_rate(void *priv, struct ieee80211_supported_band *sband,
+-                  struct ieee80211_sta *sta, void *priv_sta,
+-                  struct sk_buff *skb, struct rate_selection *sel)
++minstrel_get_rate(void *priv, struct ieee80211_sta *sta,
++                void *priv_sta, struct ieee80211_tx_rate_control *txrc)
+ {
++      struct sk_buff *skb = txrc->skb;
++      struct ieee80211_supported_band *sband = txrc->sband;
+       struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+       struct minstrel_sta_info *mi = priv_sta;
+       struct minstrel_priv *mp = priv;
+-      struct ieee80211_tx_altrate *ar = info->control.retries;
++      struct ieee80211_tx_rate *ar = info->control.rates;
+       unsigned int ndx, sample_ndx = 0;
+       bool mrr;
+       bool sample_slower = false;
+@@ -251,16 +242,12 @@ minstrel_get_rate(void *priv, struct iee
+       int sample_rate;
+       if (!sta || !mi || use_low_rate(skb)) {
+-              sel->rate_idx = rate_lowest_index(sband, sta);
++              ar[0].idx = rate_lowest_index(sband, sta);
++              ar[0].count = mp->max_retry;
+               return;
+       }
+-      mrr = mp->has_mrr;
+-
+-      /* mac80211 does not allow mrr for RTS/CTS */
+-      if ((info->flags & IEEE80211_TX_CTL_USE_RTS_CTS) ||
+-          (info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT))
+-              mrr = false;
++      mrr = mp->has_mrr && !txrc->rts && !txrc->bss_conf->use_cts_prot;
+       if (time_after(jiffies, mi->stats_update + (mp->update_interval *
+                       HZ) / 1000))
+@@ -315,13 +302,12 @@ minstrel_get_rate(void *priv, struct iee
+                       mi->sample_deferred++;
+               }
+       }
+-      sel->rate_idx = mi->r[ndx].rix;
+-      info->control.retry_limit = minstrel_get_retry_count(&mi->r[ndx], info);
++      ar[0].idx = mi->r[ndx].rix;
++      ar[0].count = minstrel_get_retry_count(&mi->r[ndx], info);
+       if (!mrr) {
+-              ar[0].rate_idx = mi->lowest_rix;
+-              ar[0].limit = mp->max_retry;
+-              ar[1].rate_idx = -1;
++              ar[1].idx = mi->lowest_rix;
++              ar[1].count = mp->max_retry;
+               return;
+       }
+@@ -336,9 +322,9 @@ minstrel_get_rate(void *priv, struct iee
+       }
+       mrr_ndx[1] = mi->max_prob_rate;
+       mrr_ndx[2] = 0;
+-      for (i = 0; i < 3; i++) {
+-              ar[i].rate_idx = mi->r[mrr_ndx[i]].rix;
+-              ar[i].limit = mi->r[mrr_ndx[i]].adjusted_retry_count;
++      for (i = 1; i < 4; i++) {
++              ar[i].idx = mi->r[mrr_ndx[i - 1]].rix;
++              ar[i].count = mi->r[mrr_ndx[i - 1]].adjusted_retry_count;
+       }
+ }
+@@ -532,13 +518,13 @@ minstrel_alloc(struct ieee80211_hw *hw, 
+       /* maximum time that the hw is allowed to stay in one MRR segment */
+       mp->segment_size = 6000;
+-      if (hw->max_altrate_tries > 0)
+-              mp->max_retry = hw->max_altrate_tries;
++      if (hw->max_rate_tries > 0)
++              mp->max_retry = hw->max_rate_tries;
+       else
+               /* safe default, does not necessarily have to match hw properties */
+               mp->max_retry = 7;
+-      if (hw->max_altrates >= 3)
++      if (hw->max_rates >= 4)
+               mp->has_mrr = true;
+       mp->hw = hw;
+--- a/net/mac80211/rc80211_pid_debugfs.c
++++ b/net/mac80211/rc80211_pid_debugfs.c
+@@ -43,6 +43,7 @@ void rate_control_pid_event_tx_status(st
+ {
+       union rc_pid_event_data evd;
++      evd.flags = stat->flags;
+       memcpy(&evd.tx_status, stat, sizeof(struct ieee80211_tx_info));
+       rate_control_pid_event(buf, RC_PID_EVENT_TYPE_TX_STATUS, &evd);
+ }
+@@ -167,8 +168,8 @@ static ssize_t rate_control_pid_events_r
+       switch (ev->type) {
+       case RC_PID_EVENT_TYPE_TX_STATUS:
+               p += snprintf(pb + p, length - p, "tx_status %u %u",
+-                            ev->data.tx_status.status.excessive_retries,
+-                            ev->data.tx_status.status.retry_count);
++                            !(ev->data.flags & IEEE80211_TX_STAT_ACK),
++                            ev->data.tx_status.status.rates[0].idx);
+               break;
+       case RC_PID_EVENT_TYPE_RATE_CHANGE:
+               p += snprintf(pb + p, length - p, "rate_change %d %d",
+--- a/net/mac80211/rc80211_pid.h
++++ b/net/mac80211/rc80211_pid.h
+@@ -61,6 +61,7 @@ enum rc_pid_event_type {
+ union rc_pid_event_data {
+       /* RC_PID_EVENT_TX_STATUS */
+       struct {
++              u32 flags;
+               struct ieee80211_tx_info tx_status;
+       };
+       /* RC_PID_EVENT_TYPE_RATE_CHANGE */
+--- a/drivers/net/wireless/zd1211rw/zd_mac.c
++++ b/drivers/net/wireless/zd1211rw/zd_mac.c
+@@ -296,15 +296,14 @@ static void zd_op_stop(struct ieee80211_
+  * If no status information has been requested, the skb is freed.
+  */
+ static void tx_status(struct ieee80211_hw *hw, struct sk_buff *skb,
+-                    u32 flags, int ackssi, bool success)
++                    int ackssi, bool success)
+ {
+       struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+-      memset(&info->status, 0, sizeof(info->status));
++      ieee80211_tx_info_clear_status(info);
+-      if (!success)
+-              info->status.excessive_retries = 1;
+-      info->flags |= flags;
++      if (success)
++              info->flags |= IEEE80211_TX_STAT_ACK;
+       info->status.ack_signal = ackssi;
+       ieee80211_tx_status_irqsafe(hw, skb);
+ }
+@@ -326,7 +325,7 @@ void zd_mac_tx_failed(struct ieee80211_h
+       if (skb == NULL)
+               return;
+-      tx_status(hw, skb, 0, 0, 0);
++      tx_status(hw, skb, 0, 0);
+ }
+ /**
+@@ -347,7 +346,7 @@ void zd_mac_tx_to_dev(struct sk_buff *sk
+       skb_pull(skb, sizeof(struct zd_ctrlset));
+       if (unlikely(error ||
+           (info->flags & IEEE80211_TX_CTL_NO_ACK))) {
+-              tx_status(hw, skb, 0, 0, !error);
++              tx_status(hw, skb, 0, !error);
+       } else {
+               struct sk_buff_head *q =
+                       &zd_hw_mac(hw)->ack_wait_queue;
+@@ -406,7 +405,8 @@ static int zd_calc_tx_length_us(u8 *serv
+ }
+ static void cs_set_control(struct zd_mac *mac, struct zd_ctrlset *cs,
+-                         struct ieee80211_hdr *header, u32 flags)
++                         struct ieee80211_hdr *header,
++                         struct ieee80211_tx_info *info)
+ {
+       /*
+        * CONTROL TODO:
+@@ -417,7 +417,7 @@ static void cs_set_control(struct zd_mac
+       cs->control = 0;
+       /* First fragment */
+-      if (flags & IEEE80211_TX_CTL_FIRST_FRAGMENT)
++      if (info->flags & IEEE80211_TX_CTL_FIRST_FRAGMENT)
+               cs->control |= ZD_CS_NEED_RANDOM_BACKOFF;
+       /* Multicast */
+@@ -428,10 +428,10 @@ static void cs_set_control(struct zd_mac
+       if (ieee80211_is_pspoll(header->frame_control))
+               cs->control |= ZD_CS_PS_POLL_FRAME;
+-      if (flags & IEEE80211_TX_CTL_USE_RTS_CTS)
++      if (info->control.rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS)
+               cs->control |= ZD_CS_RTS;
+-      if (flags & IEEE80211_TX_CTL_USE_CTS_PROTECT)
++      if (info->control.rates[0].flags & IEEE80211_TX_RC_USE_CTS_PROTECT)
+               cs->control |= ZD_CS_SELF_CTS;
+       /* FIXME: Management frame? */
+@@ -517,12 +517,12 @@ static int fill_ctrlset(struct zd_mac *m
+       txrate = ieee80211_get_tx_rate(mac->hw, info);
+       cs->modulation = txrate->hw_value;
+-      if (info->flags & IEEE80211_TX_CTL_SHORT_PREAMBLE)
++      if (info->control.rates[0].flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE)
+               cs->modulation = txrate->hw_value_short;
+       cs->tx_length = cpu_to_le16(frag_len);
+-      cs_set_control(mac, cs, hdr, info->flags);
++      cs_set_control(mac, cs, hdr, info);
+       packet_length = frag_len + sizeof(struct zd_ctrlset) + 10;
+       ZD_ASSERT(packet_length <= 0xffff);
+@@ -618,7 +618,7 @@ static int filter_ack(struct ieee80211_h
+               if (likely(!compare_ether_addr(tx_hdr->addr2, rx_hdr->addr1)))
+               {
+                       __skb_unlink(skb, q);
+-                      tx_status(hw, skb, IEEE80211_TX_STAT_ACK, stats->signal, 1);
++                      tx_status(hw, skb, stats->signal, 1);
+                       goto out;
+               }
+       }
+--- a/drivers/net/wireless/rt2x00/rt2x00dev.c
++++ b/drivers/net/wireless/rt2x00/rt2x00dev.c
+@@ -499,6 +499,7 @@ void rt2x00lib_txdone(struct queue_entry
+       struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
+       struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(entry->skb);
+       enum data_queue_qid qid = skb_get_queue_mapping(entry->skb);
++      bool rts;
+       /*
+        * Unmap the skb.
+@@ -528,14 +529,14 @@ void rt2x00lib_txdone(struct queue_entry
+       rt2x00dev->link.qual.tx_failed +=
+           test_bit(TXDONE_FAILURE, &txdesc->flags);
++        rts = !!(tx_info->control.rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS);
++
+       /*
+        * Initialize TX status
+        */
+-      memset(&tx_info->status, 0, sizeof(tx_info->status));
++      ieee80211_tx_info_clear_status(tx_info);
+       tx_info->status.ack_signal = 0;
+-      tx_info->status.excessive_retries =
+-          test_bit(TXDONE_EXCESSIVE_RETRY, &txdesc->flags);
+-      tx_info->status.retry_count = txdesc->retry;
++      tx_info->status.rates[0].count = txdesc->retry + 1;
+       if (!(tx_info->flags & IEEE80211_TX_CTL_NO_ACK)) {
+               if (test_bit(TXDONE_SUCCESS, &txdesc->flags))
+@@ -544,7 +545,7 @@ void rt2x00lib_txdone(struct queue_entry
+                       rt2x00dev->low_level_stats.dot11ACKFailureCount++;
+       }
+-      if (tx_info->flags & IEEE80211_TX_CTL_USE_RTS_CTS) {
++      if (rts) {
+               if (test_bit(TXDONE_SUCCESS, &txdesc->flags))
+                       rt2x00dev->low_level_stats.dot11RTSSuccessCount++;
+               else if (test_bit(TXDONE_FAILURE, &txdesc->flags))
+--- a/drivers/net/wireless/rt2x00/rt2x00mac.c
++++ b/drivers/net/wireless/rt2x00/rt2x00mac.c
+@@ -39,7 +39,7 @@ static int rt2x00mac_tx_rts_cts(struct r
+       unsigned int data_length;
+       int retval = 0;
+-      if (tx_info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT)
++      if (tx_info->control.rates[0].flags & IEEE80211_TX_RC_USE_CTS_PROTECT)
+               data_length = sizeof(struct ieee80211_cts);
+       else
+               data_length = sizeof(struct ieee80211_rts);
+@@ -64,11 +64,11 @@ static int rt2x00mac_tx_rts_cts(struct r
+        */
+       memcpy(skb->cb, frag_skb->cb, sizeof(skb->cb));
+       rts_info = IEEE80211_SKB_CB(skb);
+-      rts_info->flags &= ~IEEE80211_TX_CTL_USE_RTS_CTS;
+-      rts_info->flags &= ~IEEE80211_TX_CTL_USE_CTS_PROTECT;
++      rts_info->control.rates[0].flags &= ~IEEE80211_TX_RC_USE_RTS_CTS;
++      rts_info->control.rates[0].flags &= ~IEEE80211_TX_RC_USE_CTS_PROTECT;
+       rts_info->flags &= ~IEEE80211_TX_CTL_REQ_TX_STATUS;
+-      if (tx_info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT)
++      if (tx_info->control.rates[0].flags & IEEE80211_TX_RC_USE_CTS_PROTECT)
+               rts_info->flags |= IEEE80211_TX_CTL_NO_ACK;
+       else
+               rts_info->flags &= ~IEEE80211_TX_CTL_NO_ACK;
+@@ -84,7 +84,7 @@ static int rt2x00mac_tx_rts_cts(struct r
+               data_length += rt2x00crypto_tx_overhead(tx_info);
+ #endif /* CONFIG_RT2X00_LIB_CRYPTO */
+-      if (tx_info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT)
++      if (tx_info->control.rates[0].flags & IEEE80211_TX_RC_USE_CTS_PROTECT)
+               ieee80211_ctstoself_get(rt2x00dev->hw, tx_info->control.vif,
+                                       frag_skb->data, data_length, tx_info,
+                                       (struct ieee80211_cts *)(skb->data));
+@@ -146,8 +146,8 @@ int rt2x00mac_tx(struct ieee80211_hw *hw
+        * inside the hardware.
+        */
+       frame_control = le16_to_cpu(ieee80211hdr->frame_control);
+-      if ((tx_info->flags & (IEEE80211_TX_CTL_USE_RTS_CTS |
+-                             IEEE80211_TX_CTL_USE_CTS_PROTECT)) &&
++      if ((tx_info->control.rates[0].flags & (IEEE80211_TX_RC_USE_RTS_CTS |
++                                              IEEE80211_TX_RC_USE_CTS_PROTECT)) &&
+           !rt2x00dev->ops->hw->set_rts_threshold) {
+               if (rt2x00queue_available(queue) <= 1)
+                       goto exit_fail;
+--- a/drivers/net/wireless/rt2x00/rt2x00queue.c
++++ b/drivers/net/wireless/rt2x00/rt2x00queue.c
+@@ -230,8 +230,15 @@ static void rt2x00queue_create_tx_descri
+       /*
+        * Determine retry information.
+        */
+-      txdesc->retry_limit = tx_info->control.retry_limit;
+-      if (tx_info->flags & IEEE80211_TX_CTL_LONG_RETRY_LIMIT)
++      txdesc->retry_limit = tx_info->control.rates[0].count - 1;
++      /*
++       * XXX: If at this point we knew whether the HW is going to use
++       *      the RETRY_MODE bit or the retry_limit (currently all
++       *      use the RETRY_MODE bit) we could do something like b43
++       *      does, set the RETRY_MODE bit when the RC algorithm is
++       *      requesting more than the long retry limit.
++       */
++      if (tx_info->control.rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS)
+               __set_bit(ENTRY_TXD_RETRY_MODE, &txdesc->flags);
+       /*
+--- a/drivers/net/wireless/adm8211.c
++++ b/drivers/net/wireless/adm8211.c
+@@ -341,15 +341,14 @@ static void adm8211_interrupt_tci(struct
+               pci_unmap_single(priv->pdev, info->mapping,
+                                info->skb->len, PCI_DMA_TODEVICE);
+-              memset(&txi->status, 0, sizeof(txi->status));
++              ieee80211_tx_info_clear_status(txi);
++
+               skb_pull(skb, sizeof(struct adm8211_tx_hdr));
+               memcpy(skb_push(skb, info->hdrlen), skb->cb, info->hdrlen);
+-              if (!(txi->flags & IEEE80211_TX_CTL_NO_ACK)) {
+-                      if (status & TDES0_STATUS_ES)
+-                              txi->status.excessive_retries = 1;
+-                      else
+-                              txi->flags |= IEEE80211_TX_STAT_ACK;
+-              }
++              if (!(txi->flags & IEEE80211_TX_CTL_NO_ACK) &&
++                  !(status & TDES0_STATUS_ES))
++                      txi->flags |= IEEE80211_TX_STAT_ACK;
++
+               ieee80211_tx_status_irqsafe(dev, skb);
+               info->skb = NULL;
+@@ -1691,8 +1690,10 @@ static int adm8211_tx(struct ieee80211_h
+       struct ieee80211_hdr *hdr;
+       struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+       struct ieee80211_rate *txrate = ieee80211_get_tx_rate(dev, info);
++      u8 rc_flags;
+-      short_preamble = !!(txrate->flags & IEEE80211_TX_CTL_SHORT_PREAMBLE);
++      rc_flags = info->control.rates[0].flags;
++      short_preamble = !!(rc_flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE);
+       plcp_signal = txrate->bitrate;
+       hdr = (struct ieee80211_hdr *)skb->data;
+@@ -1724,10 +1725,10 @@ static int adm8211_tx(struct ieee80211_h
+       if (short_preamble)
+               txhdr->header_control |= cpu_to_le16(ADM8211_TXHDRCTL_SHORT_PREAMBLE);
+-      if (info->flags & IEEE80211_TX_CTL_USE_RTS_CTS)
++      if (rc_flags & IEEE80211_TX_RC_USE_RTS_CTS)
+               txhdr->header_control |= cpu_to_le16(ADM8211_TXHDRCTL_ENABLE_RTS);
+-      txhdr->retry_limit = info->control.retry_limit;
++      txhdr->retry_limit = info->control.rates[0].count;
+       adm8211_tx_raw(dev, skb, plcp_signal, hdrlen);
+--- a/drivers/net/wireless/ath5k/base.c
++++ b/drivers/net/wireless/ath5k/base.c
+@@ -542,8 +542,8 @@ ath5k_pci_probe(struct pci_dev *pdev,
+       /* set up multi-rate retry capabilities */
+       if (sc->ah->ah_version == AR5K_AR5212) {
+-              hw->max_altrates = 3;
+-              hw->max_altrate_tries = 11;
++              hw->max_rates = 4;
++              hw->max_rate_tries = 11;
+       }
+       /* Finish private driver data initialization */
+@@ -1188,7 +1188,7 @@ ath5k_txbuf_setup(struct ath5k_softc *sc
+               ieee80211_get_hdrlen_from_skb(skb), AR5K_PKT_TYPE_NORMAL,
+               (sc->power_level * 2),
+               ieee80211_get_tx_rate(sc->hw, info)->hw_value,
+-              info->control.retry_limit, keyidx, 0, flags, 0, 0);
++              info->control.rates[0].count, keyidx, 0, flags, 0, 0);
+       if (ret)
+               goto err_unmap;
+@@ -1200,7 +1200,7 @@ ath5k_txbuf_setup(struct ath5k_softc *sc
+                       break;
+               mrr_rate[i] = rate->hw_value;
+-              mrr_tries[i] = info->control.retries[i].limit;
++              mrr_tries[i] = info->control.rates[i + 1].count;
+       }
+       ah->ah_setup_mrr_tx_desc(ah, ds,
+@@ -1846,30 +1846,26 @@ ath5k_tx_processq(struct ath5k_softc *sc
+               pci_unmap_single(sc->pdev, bf->skbaddr, skb->len,
+                               PCI_DMA_TODEVICE);
+-              memset(&info->status, 0, sizeof(info->status));
+-              info->tx_rate_idx = ath5k_hw_to_driver_rix(sc,
+-                              ts.ts_rate[ts.ts_final_idx]);
+-              info->status.retry_count = ts.ts_longretry;
+-
++              ieee80211_tx_info_clear_status(info);
+               for (i = 0; i < 4; i++) {
+-                      struct ieee80211_tx_altrate *r =
+-                              &info->status.retries[i];
++                      struct ieee80211_tx_rate *r =
++                              &info->status.rates[i];
+                       if (ts.ts_rate[i]) {
+-                              r->rate_idx = ath5k_hw_to_driver_rix(sc, ts.ts_rate[i]);
+-                              r->limit = ts.ts_retry[i];
++                              r->idx = ath5k_hw_to_driver_rix(sc, ts.ts_rate[i]);
++                              r->count = ts.ts_retry[i];
+                       } else {
+-                              r->rate_idx = -1;
+-                              r->limit = 0;
++                              r->idx = -1;
++                              r->count = 0;
+                       }
+               }
+-              info->status.excessive_retries = 0;
++              /* count the successful attempt as well */
++              info->status.rates[ts.ts_final_idx].count++;
++
+               if (unlikely(ts.ts_status)) {
+                       sc->ll_stats.dot11ACKFailureCount++;
+-                      if (ts.ts_status & AR5K_TXERR_XRETRY)
+-                              info->status.excessive_retries = 1;
+-                      else if (ts.ts_status & AR5K_TXERR_FILT)
++                      if (ts.ts_status & AR5K_TXERR_FILT)
+                               info->flags |= IEEE80211_TX_STAT_TX_FILTERED;
+               } else {
+                       info->flags |= IEEE80211_TX_STAT_ACK;
+--- a/drivers/net/wireless/ath9k/main.c
++++ b/drivers/net/wireless/ath9k/main.c
+@@ -461,12 +461,13 @@ void ath_tx_complete(struct ath_softc *s
+       DPRINTF(sc, ATH_DBG_XMIT,
+               "%s: TX complete: skb: %p\n", __func__, skb);
++      ieee80211_tx_info_clear_status(tx_info);
+       if (tx_info->flags & IEEE80211_TX_CTL_NO_ACK ||
+               tx_info->flags & IEEE80211_TX_STAT_TX_FILTERED) {
+-              /* free driver's private data area of tx_info */
+-              if (tx_info->driver_data[0] != NULL)
+-                      kfree(tx_info->driver_data[0]);
+-                      tx_info->driver_data[0] = NULL;
++              /* free driver's private data area of tx_info, XXX: HACK! */
++              if (tx_info->control.vif != NULL)
++                      kfree(tx_info->control.vif);
++                      tx_info->control.vif = NULL;
+       }
+       if (tx_status->flags & ATH_TX_BAR) {
+@@ -474,17 +475,12 @@ void ath_tx_complete(struct ath_softc *s
+               tx_status->flags &= ~ATH_TX_BAR;
+       }
+-      if (tx_status->flags & (ATH_TX_ERROR | ATH_TX_XRETRY)) {
+-              if (!(tx_info->flags & IEEE80211_TX_CTL_NO_ACK)) {
+-                      /* Frame was not ACKed, but an ACK was expected */
+-                      tx_info->status.excessive_retries = 1;
+-              }
+-      } else {
++      if (!(tx_status->flags & (ATH_TX_ERROR | ATH_TX_XRETRY))) {
+               /* Frame was ACKed */
+               tx_info->flags |= IEEE80211_TX_STAT_ACK;
+       }
+-      tx_info->status.retry_count = tx_status->retries;
++      tx_info->status.rates[0].count = tx_status->retries + 1;
+       ieee80211_tx_status(hw, skb);
+       if (an)
+--- a/drivers/net/wireless/ath9k/rc.c
++++ b/drivers/net/wireless/ath9k/rc.c
+@@ -1864,24 +1864,21 @@ static void ath_tx_status(void *priv, st
+       hdr = (struct ieee80211_hdr *)skb->data;
+       fc = hdr->frame_control;
+-      tx_info_priv = (struct ath_tx_info_priv *)tx_info->driver_data[0];
++      /* XXX: UGLY HACK!! */
++      tx_info_priv = (struct ath_tx_info_priv *)tx_info->control.vif;
+       spin_lock_bh(&sc->node_lock);
+       an = ath_node_find(sc, hdr->addr1);
+       spin_unlock_bh(&sc->node_lock);
+-      if (!an || !priv_sta || !ieee80211_is_data(fc)) {
+-              if (tx_info->driver_data[0] != NULL) {
+-                      kfree(tx_info->driver_data[0]);
+-                      tx_info->driver_data[0] = NULL;
+-              }
++      if (tx_info_priv == NULL)
+               return;
+-      }
+-      if (tx_info->driver_data[0] != NULL) {
++
++      if (an && priv_sta && ieee80211_is_data(fc))
+               ath_rate_tx_complete(sc, an, priv_sta, tx_info_priv);
+-              kfree(tx_info->driver_data[0]);
+-              tx_info->driver_data[0] = NULL;
+-      }
++
++      kfree(tx_info_priv);
++      tx_info->control.vif = NULL;
+ }
+ static void ath_tx_aggr_resp(struct ath_softc *sc,
+@@ -1927,10 +1924,11 @@ static void ath_tx_aggr_resp(struct ath_
+       }
+ }
+-static void ath_get_rate(void *priv, struct ieee80211_supported_band *sband,
+-                       struct ieee80211_sta *sta, void *priv_sta,
+-                       struct sk_buff *skb, struct rate_selection *sel)
++static void ath_get_rate(void *priv, struct ieee80211_sta *sta, void *priv_sta,
++                       struct ieee80211_tx_rate_control *txrc)
+ {
++      struct ieee80211_supported_band *sband = txrc->sband;
++      struct sk_buff *skb = txrc->skb;
+       struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
+       struct ath_softc *sc = priv;
+       struct ieee80211_hw *hw = sc->hw;
+@@ -1946,17 +1944,17 @@ static void ath_get_rate(void *priv, str
+       DPRINTF(sc, ATH_DBG_RATE, "%s\n", __func__);
+-      /* allocate driver private area of tx_info */
+-      tx_info->driver_data[0] = kzalloc(sizeof(*tx_info_priv), GFP_ATOMIC);
+-      ASSERT(tx_info->driver_data[0] != NULL);
+-      tx_info_priv = (struct ath_tx_info_priv *)tx_info->driver_data[0];
++      /* allocate driver private area of tx_info, XXX: UGLY HACK! */
++      tx_info->control.vif = kzalloc(sizeof(*tx_info_priv), GFP_ATOMIC);
++      tx_info_priv = (struct ath_tx_info_priv *)tx_info->control.vif;
++      ASSERT(tx_info_priv != NULL);
+       lowest_idx = rate_lowest_index(sband, sta);
+       tx_info_priv->min_rate = (sband->bitrates[lowest_idx].bitrate * 2) / 10;
+       /* lowest rate for management and multicast/broadcast frames */
+       if (!ieee80211_is_data(fc) ||
+           is_multicast_ether_addr(hdr->addr1) || !sta) {
+-              sel->rate_idx = lowest_idx;
++              tx_info->control.rates[0].idx = lowest_idx;
+               return;
+       }
+@@ -1967,8 +1965,10 @@ static void ath_get_rate(void *priv, str
+                         tx_info_priv->rcs,
+                         &is_probe,
+                         false);
++#if 0
+       if (is_probe)
+               sel->probe_idx = ath_rc_priv->tx_ratectrl.probe_rate;
++#endif
+       /* Ratecontrol sometimes returns invalid rate index */
+       if (tx_info_priv->rcs[0].rix != 0xff)
+@@ -1976,7 +1976,7 @@ static void ath_get_rate(void *priv, str
+       else
+               tx_info_priv->rcs[0].rix = ath_rc_priv->prev_data_rix;
+-      sel->rate_idx = tx_info_priv->rcs[0].rix;
++      tx_info->control.rates[0].idx = tx_info_priv->rcs[0].rix;
+       /* Check if aggregation has to be enabled for this tid */
+--- a/drivers/net/wireless/ath9k/xmit.c
++++ b/drivers/net/wireless/ath9k/xmit.c
+@@ -168,7 +168,9 @@ static void fill_min_rates(struct sk_buf
+       hdr = (struct ieee80211_hdr *)skb->data;
+       fc = hdr->frame_control;
+-      tx_info_priv = (struct ath_tx_info_priv *)tx_info->driver_data[0];
++
++      /* XXX: HACK! */
++      tx_info_priv = (struct ath_tx_info_priv *)tx_info->control.vif;
+       if (ieee80211_is_mgmt(fc) || ieee80211_is_ctl(fc)) {
+               txctl->use_minrate = 1;
+@@ -288,13 +290,16 @@ static int ath_tx_prepare(struct ath_sof
+       if (tx_info->flags & IEEE80211_TX_CTL_NO_ACK)
+               txctl->flags |= ATH9K_TXDESC_NOACK;
+-      if (tx_info->flags & IEEE80211_TX_CTL_USE_RTS_CTS)
++
++      if (tx_info->control.rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS)
+               txctl->flags |= ATH9K_TXDESC_RTSENA;
+       /*
+        * Setup for rate calculations.
+        */
+-      tx_info_priv = (struct ath_tx_info_priv *)tx_info->driver_data[0];
++
++      /* XXX: HACK! */
++      tx_info_priv = (struct ath_tx_info_priv *)tx_info->control.vif;
+       rcs = tx_info_priv->rcs;
+       if (ieee80211_is_data(fc) && !txctl->use_minrate) {
+@@ -854,7 +859,9 @@ static int ath_tx_send_normal(struct ath
+       skb = (struct sk_buff *)bf->bf_mpdu;
+       tx_info = IEEE80211_SKB_CB(skb);
+-      tx_info_priv = (struct ath_tx_info_priv *)tx_info->driver_data[0];
++
++      /* XXX: HACK! */
++      tx_info_priv = (struct ath_tx_info_priv *)tx_info->control.vif;
+       memcpy(bf->bf_rcs, tx_info_priv->rcs, 4 * sizeof(tx_info_priv->rcs[0]));
+       /* update starting sequence number for subsequent ADDBA request */
+@@ -1248,8 +1255,9 @@ static int ath_tx_processq(struct ath_so
+               }
+               skb = bf->bf_mpdu;
+               tx_info = IEEE80211_SKB_CB(skb);
+-              tx_info_priv = (struct ath_tx_info_priv *)
+-                      tx_info->driver_data[0];
++
++              /* XXX: HACK! */
++              tx_info_priv = (struct ath_tx_info_priv *) tx_info->control.vif;
+               if (ds->ds_txstat.ts_status & ATH9K_TXERR_FILT)
+                       tx_info->flags |= IEEE80211_TX_STAT_TX_FILTERED;
+               if ((ds->ds_txstat.ts_status & ATH9K_TXERR_FILT) == 0 &&
+@@ -1430,7 +1438,8 @@ static int ath_tx_send_ampdu(struct ath_
+       skb = (struct sk_buff *)bf->bf_mpdu;
+       tx_info = IEEE80211_SKB_CB(skb);
+-      tx_info_priv = (struct ath_tx_info_priv *)tx_info->driver_data[0];
++      /* XXX: HACK! */
++      tx_info_priv = (struct ath_tx_info_priv *)tx_info->control.vif;
+       memcpy(bf->bf_rcs, tx_info_priv->rcs, 4 * sizeof(tx_info_priv->rcs[0]));
+       /* Add sub-frame to BAW */
+@@ -1464,7 +1473,7 @@ static u32 ath_lookup_rate(struct ath_so
+       skb = (struct sk_buff *)bf->bf_mpdu;
+       tx_info = IEEE80211_SKB_CB(skb);
+       tx_info_priv = (struct ath_tx_info_priv *)
+-              tx_info->driver_data[0];
++              tx_info->control.vif; /* XXX: HACK! */
+       memcpy(bf->bf_rcs,
+               tx_info_priv->rcs, 4 * sizeof(tx_info_priv->rcs[0]));
+@@ -1924,7 +1933,8 @@ static int ath_tx_start_dma(struct ath_s
+       bf->bf_flags = txctl->flags;
+       bf->bf_keytype = txctl->keytype;
+-      tx_info_priv = (struct ath_tx_info_priv *)tx_info->driver_data[0];
++      /* XXX: HACK! */
++      tx_info_priv = (struct ath_tx_info_priv *)tx_info->control.vif;
+       rcs = tx_info_priv->rcs;
+       bf->bf_rcs[0] = rcs[0];
+       bf->bf_rcs[1] = rcs[1];
+--- a/drivers/net/wireless/b43/dma.c
++++ b/drivers/net/wireless/b43/dma.c
+@@ -1387,13 +1387,13 @@ void b43_dma_handle_txstatus(struct b43_
+                       info = IEEE80211_SKB_CB(meta->skb);
+-                      memset(&info->status, 0, sizeof(info->status));
++                      ieee80211_tx_info_clear_status(info);
+                       /*
+                        * Call back to inform the ieee80211 subsystem about
+                        * the status of the transmission.
+                        */
+-                      frame_succeed = b43_fill_txstatus_report(info, status);
++                      frame_succeed = b43_fill_txstatus_report(dev, info, status);
+ #ifdef CONFIG_B43_DEBUG
+                       if (frame_succeed)
+                               ring->nr_succeed_tx_packets++;
+--- a/drivers/net/wireless/b43/main.c
++++ b/drivers/net/wireless/b43/main.c
+@@ -4563,7 +4563,7 @@ static int b43_wireless_init(struct ssb_
+               BIT(NL80211_IFTYPE_ADHOC);
+       hw->queues = b43_modparam_qos ? 4 : 1;
+-      hw->max_altrates = 1;
++      hw->max_rates = 2;
+       SET_IEEE80211_DEV(hw, dev->dev);
+       if (is_valid_ether_addr(sprom->et1mac))
+               SET_IEEE80211_PERM_ADDR(hw, sprom->et1mac);
+--- a/drivers/net/wireless/b43/pio.c
++++ b/drivers/net/wireless/b43/pio.c
+@@ -587,9 +587,9 @@ void b43_pio_handle_txstatus(struct b43_
+       spin_lock(&q->lock); /* IRQs are already disabled. */
+       info = IEEE80211_SKB_CB(pack->skb);
+-      memset(&info->status, 0, sizeof(info->status));
++      ieee80211_tx_info_clear_status(info);
+-      b43_fill_txstatus_report(info, status);
++      b43_fill_txstatus_report(dev, info, status);
+       total_len = pack->skb->len + b43_txhdr_size(dev);
+       total_len = roundup(total_len, 4);
+--- a/drivers/net/wireless/b43/xmit.c
++++ b/drivers/net/wireless/b43/xmit.c
+@@ -185,7 +185,7 @@ int b43_generate_txhdr(struct b43_wldev 
+                      u8 *_txhdr,
+                      const unsigned char *fragment_data,
+                      unsigned int fragment_len,
+-                     const struct ieee80211_tx_info *info,
++                     struct ieee80211_tx_info *info,
+                      u16 cookie)
+ {
+       struct b43_txhdr *txhdr = (struct b43_txhdr *)_txhdr;
+@@ -202,6 +202,7 @@ int b43_generate_txhdr(struct b43_wldev 
+       u16 phy_ctl = 0;
+       u8 extra_ft = 0;
+       struct ieee80211_rate *txrate;
++      struct ieee80211_tx_rate *rates;
+       memset(txhdr, 0, sizeof(*txhdr));
+@@ -291,7 +292,7 @@ int b43_generate_txhdr(struct b43_wldev 
+               phy_ctl |= B43_TXH_PHY_ENC_OFDM;
+       else
+               phy_ctl |= B43_TXH_PHY_ENC_CCK;
+-      if (info->flags & IEEE80211_TX_CTL_SHORT_PREAMBLE)
++      if (info->control.rates[0].flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE)
+               phy_ctl |= B43_TXH_PHY_SHORTPRMBL;
+       switch (b43_ieee80211_antenna_sanitize(dev, info->antenna_sel_tx)) {
+@@ -314,6 +315,7 @@ int b43_generate_txhdr(struct b43_wldev 
+               B43_WARN_ON(1);
+       }
++      rates = info->control.rates;
+       /* MAC control */
+       if (!(info->flags & IEEE80211_TX_CTL_NO_ACK))
+               mac_ctl |= B43_TXH_MAC_ACK;
+@@ -324,12 +326,22 @@ int b43_generate_txhdr(struct b43_wldev 
+               mac_ctl |= B43_TXH_MAC_STMSDU;
+       if (phy->type == B43_PHYTYPE_A)
+               mac_ctl |= B43_TXH_MAC_5GHZ;
+-      if (info->flags & IEEE80211_TX_CTL_LONG_RETRY_LIMIT)
++
++      /* Overwrite rates[0].count to make the retry calculation
++       * in the tx status easier. need the actual retry limit to
++       * detect whether the fallback rate was used.
++       */
++      if ((rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS) ||
++          (rates[0].count <= dev->wl->hw->conf.long_frame_max_tx_count)) {
++              rates[0].count = dev->wl->hw->conf.long_frame_max_tx_count;
+               mac_ctl |= B43_TXH_MAC_LONGFRAME;
++      } else {
++              rates[0].count = dev->wl->hw->conf.short_frame_max_tx_count;
++      }
+       /* Generate the RTS or CTS-to-self frame */
+-      if ((info->flags & IEEE80211_TX_CTL_USE_RTS_CTS) ||
+-          (info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT)) {
++      if ((rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS) ||
++          (rates[0].flags & IEEE80211_TX_RC_USE_CTS_PROTECT)) {
+               unsigned int len;
+               struct ieee80211_hdr *hdr;
+               int rts_rate, rts_rate_fb;
+@@ -344,7 +356,7 @@ int b43_generate_txhdr(struct b43_wldev 
+               rts_rate_fb = b43_calc_fallback_rate(rts_rate);
+               rts_rate_fb_ofdm = b43_is_ofdm_rate(rts_rate_fb);
+-              if (info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT) {
++              if (rates[0].flags & IEEE80211_TX_RC_USE_CTS_PROTECT) {
+                       struct ieee80211_cts *cts;
+                       if (b43_is_old_txhdr_format(dev)) {
+@@ -687,10 +699,18 @@ void b43_handle_txstatus(struct b43_wlde
+ /* Fill out the mac80211 TXstatus report based on the b43-specific
+  * txstatus report data. This returns a boolean whether the frame was
+  * successfully transmitted. */
+-bool b43_fill_txstatus_report(struct ieee80211_tx_info *report,
++bool b43_fill_txstatus_report(struct b43_wldev *dev,
++                            struct ieee80211_tx_info *report,
+                             const struct b43_txstatus *status)
+ {
+       bool frame_success = 1;
++      int retry_limit;
++
++      /* preserve the confiured retry limit before clearing the status
++       * The xmit function has overwritten the rc's value with the actual
++       * retry limit done by the hardware */
++      retry_limit = report->status.rates[0].count;
++      ieee80211_tx_info_clear_status(report);
+       if (status->acked) {
+               /* The frame was ACKed. */
+@@ -700,14 +720,32 @@ bool b43_fill_txstatus_report(struct iee
+               if (!(report->flags & IEEE80211_TX_CTL_NO_ACK)) {
+                       /* ...but we expected an ACK. */
+                       frame_success = 0;
+-                      report->status.excessive_retries = 1;
+               }
+       }
+       if (status->frame_count == 0) {
+               /* The frame was not transmitted at all. */
+-              report->status.retry_count = 0;
+-      } else
+-              report->status.retry_count = status->frame_count - 1;
++              report->status.rates[0].count = 0;
++      } else if (status->rts_count > dev->wl->hw->conf.short_frame_max_tx_count) {
++              /*
++               * If the short retries (RTS, not data frame) have exceeded
++               * the limit, the hw will not have tried the selected rate,
++               * but will have used the fallback rate instead.
++               * Don't let the rate control count attempts for the selected
++               * rate in this case, otherwise the statistics will be off.
++               */
++              report->status.rates[0].count = 0;
++              report->status.rates[1].count = status->frame_count;
++      } else {
++              if (status->frame_count > retry_limit) {
++                      report->status.rates[0].count = retry_limit;
++                      report->status.rates[1].count = status->frame_count -
++                                      retry_limit;
++
++              } else {
++                      report->status.rates[0].count = status->frame_count;
++                      report->status.rates[1].idx = -1;
++              }
++      }
+       return frame_success;
+ }
+--- a/drivers/net/wireless/b43/xmit.h
++++ b/drivers/net/wireless/b43/xmit.h
+@@ -178,7 +178,7 @@ int b43_generate_txhdr(struct b43_wldev 
+                      u8 * txhdr,
+                      const unsigned char *fragment_data,
+                      unsigned int fragment_len,
+-                     const struct ieee80211_tx_info *txctl, u16 cookie);
++                     struct ieee80211_tx_info *txctl, u16 cookie);
+ /* Transmit Status */
+ struct b43_txstatus {
+@@ -294,7 +294,8 @@ void b43_rx(struct b43_wldev *dev, struc
+ void b43_handle_txstatus(struct b43_wldev *dev,
+                        const struct b43_txstatus *status);
+-bool b43_fill_txstatus_report(struct ieee80211_tx_info *report,
++bool b43_fill_txstatus_report(struct b43_wldev *dev,
++                            struct ieee80211_tx_info *report,
+                             const struct b43_txstatus *status);
+ void b43_tx_suspend(struct b43_wldev *dev);
+--- a/drivers/net/wireless/b43legacy/dma.c
++++ b/drivers/net/wireless/b43legacy/dma.c
+@@ -1411,6 +1411,7 @@ void b43legacy_dma_handle_txstatus(struc
+       struct b43legacy_dmaring *ring;
+       struct b43legacy_dmadesc_generic *desc;
+       struct b43legacy_dmadesc_meta *meta;
++      int retry_limit;
+       int slot;
+       ring = parse_cookie(dev, status->cookie, &slot);
+@@ -1437,25 +1438,42 @@ void b43legacy_dma_handle_txstatus(struc
+                       struct ieee80211_tx_info *info;
+                       BUG_ON(!meta->skb);
+                       info = IEEE80211_SKB_CB(meta->skb);
+-                      /* Call back to inform the ieee80211 subsystem about the
+-                       * status of the transmission.
+-                       * Some fields of txstat are already filled in dma_tx().
+-                       */
+-                      memset(&info->status, 0, sizeof(info->status));
++                      /* preserve the confiured retry limit before clearing the status
++                       * The xmit function has overwritten the rc's value with the actual
++                       * retry limit done by the hardware */
++                      retry_limit = info->status.rates[0].count;
++                      ieee80211_tx_info_clear_status(info);
+-                      if (status->acked) {
++                      if (status->acked)
+                               info->flags |= IEEE80211_TX_STAT_ACK;
++
++                      if (status->rts_count > dev->wl->hw->conf.short_frame_max_tx_count) {
++                              /*
++                               * If the short retries (RTS, not data frame) have exceeded
++                               * the limit, the hw will not have tried the selected rate,
++                               * but will have used the fallback rate instead.
++                               * Don't let the rate control count attempts for the selected
++                               * rate in this case, otherwise the statistics will be off.
++                               */
++                              info->status.rates[0].count = 0;
++                              info->status.rates[1].count = status->frame_count;
+                       } else {
+-                              if (!(info->flags & IEEE80211_TX_CTL_NO_ACK))
+-                                       info->status.excessive_retries = 1;
++                              if (status->frame_count > retry_limit) {
++                                      info->status.rates[0].count = retry_limit;
++                                      info->status.rates[1].count = status->frame_count -
++                                                      retry_limit;
++
++                              } else {
++                                      info->status.rates[0].count = status->frame_count;
++                                      info->status.rates[1].idx = -1;
++                              }
+                       }
+-                      if (status->frame_count == 0) {
+-                              /* The frame was not transmitted at all. */
+-                              info->status.retry_count = 0;
+-                      } else
+-                              info->status.retry_count = status->frame_count
+-                                                         - 1;
++
++                      /* Call back to inform the ieee80211 subsystem about the
++                       * status of the transmission.
++                       * Some fields of txstat are already filled in dma_tx().
++                       */
+                       ieee80211_tx_status_irqsafe(dev->wl->hw, meta->skb);
+                       /* skb is freed by ieee80211_tx_status_irqsafe() */
+                       meta->skb = NULL;
+--- a/drivers/net/wireless/b43legacy/main.c
++++ b/drivers/net/wireless/b43legacy/main.c
+@@ -3691,7 +3691,7 @@ static int b43legacy_wireless_init(struc
+               BIT(NL80211_IFTYPE_WDS) |
+               BIT(NL80211_IFTYPE_ADHOC);
+       hw->queues = 1; /* FIXME: hardware has more queues */
+-      hw->max_altrates = 1;
++      hw->max_rates = 2;
+       SET_IEEE80211_DEV(hw, dev->dev);
+       if (is_valid_ether_addr(sprom->et1mac))
+               SET_IEEE80211_PERM_ADDR(hw, sprom->et1mac);
+--- a/drivers/net/wireless/b43legacy/pio.c
++++ b/drivers/net/wireless/b43legacy/pio.c
+@@ -491,6 +491,7 @@ void b43legacy_pio_handle_txstatus(struc
+       struct b43legacy_pioqueue *queue;
+       struct b43legacy_pio_txpacket *packet;
+       struct ieee80211_tx_info *info;
++      int retry_limit;
+       queue = parse_cookie(dev, status->cookie, &packet);
+       B43legacy_WARN_ON(!queue);
+@@ -503,11 +504,37 @@ void b43legacy_pio_handle_txstatus(struc
+                               sizeof(struct b43legacy_txhdr_fw3));
+       info = IEEE80211_SKB_CB(packet->skb);
+-      memset(&info->status, 0, sizeof(info->status));
++
++      /* preserve the confiured retry limit before clearing the status
++       * The xmit function has overwritten the rc's value with the actual
++       * retry limit done by the hardware */
++      retry_limit = info->status.rates[0].count;
++      ieee80211_tx_info_clear_status(info);
+       if (status->acked)
+               info->flags |= IEEE80211_TX_STAT_ACK;
+-      info->status.retry_count = status->frame_count - 1;
++
++      if (status->rts_count > dev->wl->hw->conf.short_frame_max_tx_count) {
++              /*
++               * If the short retries (RTS, not data frame) have exceeded
++               * the limit, the hw will not have tried the selected rate,
++               * but will have used the fallback rate instead.
++               * Don't let the rate control count attempts for the selected
++               * rate in this case, otherwise the statistics will be off.
++               */
++              info->status.rates[0].count = 0;
++              info->status.rates[1].count = status->frame_count;
++      } else {
++              if (status->frame_count > retry_limit) {
++                      info->status.rates[0].count = retry_limit;
++                      info->status.rates[1].count = status->frame_count -
++                                      retry_limit;
++
++              } else {
++                      info->status.rates[0].count = status->frame_count;
++                      info->status.rates[1].idx = -1;
++              }
++      }
+       ieee80211_tx_status_irqsafe(dev->wl->hw, packet->skb);
+       packet->skb = NULL;
+--- a/drivers/net/wireless/b43legacy/xmit.c
++++ b/drivers/net/wireless/b43legacy/xmit.c
+@@ -188,7 +188,7 @@ static int generate_txhdr_fw3(struct b43
+                              struct b43legacy_txhdr_fw3 *txhdr,
+                              const unsigned char *fragment_data,
+                              unsigned int fragment_len,
+-                             const struct ieee80211_tx_info *info,
++                             struct ieee80211_tx_info *info,
+                              u16 cookie)
+ {
+       const struct ieee80211_hdr *wlhdr;
+@@ -201,6 +201,7 @@ static int generate_txhdr_fw3(struct b43
+       u32 mac_ctl = 0;
+       u16 phy_ctl = 0;
+       struct ieee80211_rate *tx_rate;
++      struct ieee80211_tx_rate *rates;
+       wlhdr = (const struct ieee80211_hdr *)fragment_data;
+@@ -274,7 +275,7 @@ static int generate_txhdr_fw3(struct b43
+       /* PHY TX Control word */
+       if (rate_ofdm)
+               phy_ctl |= B43legacy_TX4_PHY_OFDM;
+-      if (dev->short_preamble)
++      if (info->control.rates[0].flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE)
+               phy_ctl |= B43legacy_TX4_PHY_SHORTPRMBL;
+       switch (info->antenna_sel_tx) {
+       case 0:
+@@ -291,6 +292,7 @@ static int generate_txhdr_fw3(struct b43
+       }
+       /* MAC control */
++      rates = info->control.rates;
+       if (!(info->flags & IEEE80211_TX_CTL_NO_ACK))
+               mac_ctl |= B43legacy_TX4_MAC_ACK;
+       if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ)
+@@ -299,12 +301,22 @@ static int generate_txhdr_fw3(struct b43
+               mac_ctl |= B43legacy_TX4_MAC_STMSDU;
+       if (rate_fb_ofdm)
+               mac_ctl |= B43legacy_TX4_MAC_FALLBACKOFDM;
+-      if (info->flags & IEEE80211_TX_CTL_LONG_RETRY_LIMIT)
++
++      /* Overwrite rates[0].count to make the retry calculation
++       * in the tx status easier. need the actual retry limit to
++       * detect whether the fallback rate was used.
++       */
++      if ((rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS) ||
++          (rates[0].count <= dev->wl->hw->conf.long_frame_max_tx_count)) {
++              rates[0].count = dev->wl->hw->conf.long_frame_max_tx_count;
+               mac_ctl |= B43legacy_TX4_MAC_LONGFRAME;
++      } else {
++              rates[0].count = dev->wl->hw->conf.short_frame_max_tx_count;
++      }
+       /* Generate the RTS or CTS-to-self frame */
+-      if ((info->flags & IEEE80211_TX_CTL_USE_RTS_CTS) ||
+-          (info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT)) {
++      if ((rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS) ||
++          (rates[0].flags & IEEE80211_TX_RC_USE_CTS_PROTECT)) {
+               unsigned int len;
+               struct ieee80211_hdr *hdr;
+               int rts_rate;
+@@ -319,7 +331,7 @@ static int generate_txhdr_fw3(struct b43
+               if (rts_rate_fb_ofdm)
+                       mac_ctl |= B43legacy_TX4_MAC_CTSFALLBACKOFDM;
+-              if (info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT) {
++              if (rates[0].flags & IEEE80211_TX_RC_USE_CTS_PROTECT) {
+                       ieee80211_ctstoself_get(dev->wl->hw,
+                                               info->control.vif,
+                                               fragment_data,
+@@ -362,7 +374,7 @@ int b43legacy_generate_txhdr(struct b43l
+                             u8 *txhdr,
+                             const unsigned char *fragment_data,
+                             unsigned int fragment_len,
+-                            const struct ieee80211_tx_info *info,
++                            struct ieee80211_tx_info *info,
+                             u16 cookie)
+ {
+       return generate_txhdr_fw3(dev, (struct b43legacy_txhdr_fw3 *)txhdr,
+--- a/drivers/net/wireless/b43legacy/xmit.h
++++ b/drivers/net/wireless/b43legacy/xmit.h
+@@ -80,7 +80,7 @@ int b43legacy_generate_txhdr(struct b43l
+                             u8 *txhdr,
+                             const unsigned char *fragment_data,
+                             unsigned int fragment_len,
+-                            const struct ieee80211_tx_info *info,
++                            struct ieee80211_tx_info *info,
+                             u16 cookie);
+--- a/drivers/net/wireless/iwlwifi/iwl-3945-rs.c
++++ b/drivers/net/wireless/iwlwifi/iwl-3945-rs.c
+@@ -422,34 +422,6 @@ static void rs_free_sta(void *priv, stru
+ }
+-/*
+- * get ieee prev rate from rate scale table.
+- * for A and B mode we need to overright prev
+- * value
+- */
+-static int rs_adjust_next_rate(struct iwl3945_priv *priv, int rate)
+-{
+-      int next_rate = iwl3945_get_prev_ieee_rate(rate);
+-
+-      switch (priv->band) {
+-      case IEEE80211_BAND_5GHZ:
+-              if (rate == IWL_RATE_12M_INDEX)
+-                      next_rate = IWL_RATE_9M_INDEX;
+-              else if (rate == IWL_RATE_6M_INDEX)
+-                      next_rate = IWL_RATE_6M_INDEX;
+-              break;
+-/* XXX cannot be invoked in current mac80211 so not a regression
+-      case MODE_IEEE80211B:
+-              if (rate == IWL_RATE_11M_INDEX_TABLE)
+-                      next_rate = IWL_RATE_5M_INDEX_TABLE;
+-              break;
+- */
+-      default:
+-              break;
+-      }
+-
+-      return next_rate;
+-}
+ /**
+  * rs_tx_status - Update rate control values based on Tx results
+  *
+@@ -460,17 +432,21 @@ static void rs_tx_status(void *priv_rate
+                        struct ieee80211_sta *sta, void *priv_sta,
+                        struct sk_buff *skb)
+ {
+-      u8 retries, current_count;
++      u8 retries = 0, current_count;
+       int scale_rate_index, first_index, last_index;
+       unsigned long flags;
+       struct iwl3945_priv *priv = (struct iwl3945_priv *)priv_rate;
+       struct iwl3945_rs_sta *rs_sta = priv_sta;
+       struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
++      int i;
+       IWL_DEBUG_RATE("enter\n");
+-      retries = info->status.retry_count;
+-      first_index = sband->bitrates[info->tx_rate_idx].hw_value;
++      for (i = 0; i < IEEE80211_TX_MAX_RATES; i++)
++              retries += info->status.rates[i].count;
++      retries--;
++
++      first_index = sband->bitrates[info->status.rates[0].idx].hw_value;
+       if ((first_index < 0) || (first_index >= IWL_RATE_COUNT)) {
+               IWL_DEBUG_RATE("leave: Rate out of bounds: %d\n", first_index);
+               return;
+@@ -502,7 +478,7 @@ static void rs_tx_status(void *priv_rate
+                       last_index = scale_rate_index;
+               } else {
+                       current_count = priv->retry_rate;
+-                      last_index = rs_adjust_next_rate(priv,
++                      last_index = iwl3945_rs_next_rate(priv,
+                                                        scale_rate_index);
+               }
+@@ -518,7 +494,7 @@ static void rs_tx_status(void *priv_rate
+               if (retries)
+                       scale_rate_index =
+-                          rs_adjust_next_rate(priv, scale_rate_index);
++                          iwl3945_rs_next_rate(priv, scale_rate_index);
+       }
+@@ -630,10 +606,11 @@ static u16 iwl3945_get_adjacent_rate(str
+  * rate table and must reference the driver allocated rate table
+  *
+  */
+-static void rs_get_rate(void *priv_r, struct ieee80211_supported_band *sband,
+-                      struct ieee80211_sta *sta, void *priv_sta,
+-                      struct sk_buff *skb, struct rate_selection *sel)
++static void rs_get_rate(void *priv_r, struct ieee80211_sta *sta,
++                      void *priv_sta, struct ieee80211_tx_rate_control *txrc)
+ {
++      struct ieee80211_supported_band *sband = txrc->sband;
++      struct sk_buff *skb = txrc->skb;
+       u8 low = IWL_RATE_INVALID;
+       u8 high = IWL_RATE_INVALID;
+       u16 high_low;
+@@ -649,6 +626,7 @@ static void rs_get_rate(void *priv_r, st
+       struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
+       u16 fc, rate_mask;
+       struct iwl3945_priv *priv = (struct iwl3945_priv *)priv_r;
++      struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+       DECLARE_MAC_BUF(mac);
+       IWL_DEBUG_RATE("enter\n");
+@@ -660,7 +638,7 @@ static void rs_get_rate(void *priv_r, st
+           is_multicast_ether_addr(hdr->addr1) ||
+           !sta || !priv_sta) {
+               IWL_DEBUG_RATE("leave: No STA priv data to update!\n");
+-              sel->rate_idx = rate_lowest_index(sband, sta);
++              info->control.rates[0].idx = rate_lowest_index(sband, sta);
+               return;
+       }
+@@ -793,9 +771,10 @@ static void rs_get_rate(void *priv_r, st
+       rs_sta->last_txrate_idx = index;
+       if (sband->band == IEEE80211_BAND_5GHZ)
+-              sel->rate_idx = rs_sta->last_txrate_idx - IWL_FIRST_OFDM_RATE;
++              info->control.rates[0].idx = rs_sta->last_txrate_idx -
++                              IWL_FIRST_OFDM_RATE;
+       else
+-              sel->rate_idx = rs_sta->last_txrate_idx;
++              info->control.rates[0].idx = rs_sta->last_txrate_idx;
+       IWL_DEBUG_RATE("leave: %d\n", index);
+ }
+--- a/drivers/net/wireless/iwlwifi/iwl-3945.c
++++ b/drivers/net/wireless/iwlwifi/iwl-3945.c
+@@ -261,6 +261,35 @@ static inline const char *iwl3945_get_tx
+ }
+ #endif
++/*
++ * get ieee prev rate from rate scale table.
++ * for A and B mode we need to overright prev
++ * value
++ */
++int iwl3945_rs_next_rate(struct iwl3945_priv *priv, int rate)
++{
++      int next_rate = iwl3945_get_prev_ieee_rate(rate);
++
++      switch (priv->band) {
++      case IEEE80211_BAND_5GHZ:
++              if (rate == IWL_RATE_12M_INDEX)
++                      next_rate = IWL_RATE_9M_INDEX;
++              else if (rate == IWL_RATE_6M_INDEX)
++                      next_rate = IWL_RATE_6M_INDEX;
++              break;
++/* XXX cannot be invoked in current mac80211 so not a regression
++      case MODE_IEEE80211B:
++              if (rate == IWL_RATE_11M_INDEX_TABLE)
++                      next_rate = IWL_RATE_5M_INDEX_TABLE;
++              break;
++ */
++      default:
++              break;
++      }
++
++      return next_rate;
++}
++
+ /**
+  * iwl3945_tx_queue_reclaim - Reclaim Tx queue entries already Tx'd
+@@ -308,6 +337,7 @@ static void iwl3945_rx_reply_tx(struct i
+       struct iwl3945_tx_resp *tx_resp = (void *)&pkt->u.raw[0];
+       u32  status = le32_to_cpu(tx_resp->status);
+       int rate_idx;
++      int fail, i;
+       if ((index >= txq->q.n_bd) || (iwl3945_x2_queue_used(&txq->q, index) == 0)) {
+               IWL_ERROR("Read index for DMA queue txq_id (%d) index %d "
+@@ -318,9 +348,33 @@ static void iwl3945_rx_reply_tx(struct i
+       }
+       info = IEEE80211_SKB_CB(txq->txb[txq->q.read_ptr].skb[0]);
+-      memset(&info->status, 0, sizeof(info->status));
++      ieee80211_tx_info_clear_status(info);
++
++      /* Fill the MRR chain with some info about on-chip retransmissions */
++      rate_idx = iwl3945_hwrate_to_plcp_idx(tx_resp->rate);
++      if (info->band == IEEE80211_BAND_5GHZ)
++              rate_idx -= IWL_FIRST_OFDM_RATE;
++
++      info->status.rates[0].count = tx_resp->failure_frame + 1;
++      fail = tx_resp->failure_frame;
++      for(i = 0; i < 4; i++) {
++              int next = iwl3945_rs_next_rate(priv, rate_idx);
++
++              info->status.rates[i].idx = rate_idx;
++
++              if ((rate_idx == next) || (i == 3)) {
++                      info->status.rates[i].count = fail;
++                      break;
++              }
++
++              info->status.rates[i].count = priv->retry_rate;
++              fail -= priv->retry_rate;
++              rate_idx = next;
++              if (fail <= 0)
++                      break;
++      }
++      info->status.rates[i].count++; /* add final attempt */
+-      info->status.retry_count = tx_resp->failure_frame;
+       /* tx_status->rts_retry_count = tx_resp->failure_rts; */
+       info->flags |= ((status & TX_STATUS_MSK) == TX_STATUS_SUCCESS) ?
+                               IEEE80211_TX_STAT_ACK : 0;
+@@ -329,10 +383,6 @@ static void iwl3945_rx_reply_tx(struct i
+                       txq_id, iwl3945_get_tx_fail_reason(status), status,
+                       tx_resp->rate, tx_resp->failure_frame);
+-      rate_idx = iwl3945_hwrate_to_plcp_idx(tx_resp->rate);
+-      if (info->band == IEEE80211_BAND_5GHZ)
+-              rate_idx -= IWL_FIRST_OFDM_RATE;
+-      info->tx_rate_idx = rate_idx;
+       IWL_DEBUG_TX_REPLY("Tx queue reclaim %d\n", index);
+       iwl3945_tx_queue_reclaim(priv, txq_id, index);
+--- a/drivers/net/wireless/iwlwifi/iwl-3945.h
++++ b/drivers/net/wireless/iwlwifi/iwl-3945.h
+@@ -954,6 +954,8 @@ static inline int is_channel_ibss(const 
+ extern const struct iwl3945_channel_info *iwl3945_get_channel_info(
+       const struct iwl3945_priv *priv, enum ieee80211_band band, u16 channel);
++extern int iwl3945_rs_next_rate(struct iwl3945_priv *priv, int rate);
++
+ /* Requires full declaration of iwl3945_priv before including */
+ #include "iwl-3945-io.h"
+--- a/drivers/net/wireless/iwlwifi/iwl-core.c
++++ b/drivers/net/wireless/iwlwifi/iwl-core.c
+@@ -88,26 +88,27 @@ EXPORT_SYMBOL(iwl_rates);
+  * translate ucode response to mac80211 tx status control values
+  */
+ void iwl_hwrate_to_tx_control(struct iwl_priv *priv, u32 rate_n_flags,
+-                                struct ieee80211_tx_info *control)
++                                struct ieee80211_tx_info *info)
+ {
+       int rate_index;
++      struct ieee80211_tx_rate *r = &info->control.rates[0];
+-      control->antenna_sel_tx =
++      info->antenna_sel_tx =
+               ((rate_n_flags & RATE_MCS_ANT_ABC_MSK) >> RATE_MCS_ANT_POS);
+       if (rate_n_flags & RATE_MCS_HT_MSK)
+-              control->flags |= IEEE80211_TX_CTL_OFDM_HT;
++              r->flags |= IEEE80211_TX_RC_MCS;
+       if (rate_n_flags & RATE_MCS_GF_MSK)
+-              control->flags |= IEEE80211_TX_CTL_GREEN_FIELD;
++              r->flags |= IEEE80211_TX_RC_GREEN_FIELD;
+       if (rate_n_flags & RATE_MCS_FAT_MSK)
+-              control->flags |= IEEE80211_TX_CTL_40_MHZ_WIDTH;
++              r->flags |= IEEE80211_TX_RC_40_MHZ_WIDTH;
+       if (rate_n_flags & RATE_MCS_DUP_MSK)
+-              control->flags |= IEEE80211_TX_CTL_DUP_DATA;
++              r->flags |= IEEE80211_TX_RC_DUP_DATA;
+       if (rate_n_flags & RATE_MCS_SGI_MSK)
+-              control->flags |= IEEE80211_TX_CTL_SHORT_GI;
++              r->flags |= IEEE80211_TX_RC_SHORT_GI;
+       rate_index = iwl_hwrate_to_plcp_idx(rate_n_flags);
+-      if (control->band == IEEE80211_BAND_5GHZ)
++      if (info->band == IEEE80211_BAND_5GHZ)
+               rate_index -= IWL_FIRST_OFDM_RATE;
+-      control->tx_rate_idx = rate_index;
++      r->idx = rate_index;
+ }
+ EXPORT_SYMBOL(iwl_hwrate_to_tx_control);
+--- a/drivers/net/wireless/iwlwifi/iwl3945-base.c
++++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c
+@@ -2397,6 +2397,7 @@ static void iwl3945_build_tx_cmd_basic(s
+ {
+       __le16 fc = hdr->frame_control;
+       __le32 tx_flags = cmd->cmd.tx.tx_flags;
++      u8 rc_flags = info->control.rates[0].flags;
+       cmd->cmd.tx.stop_time.life_time = TX_CMD_LIFE_TIME_INFINITE;
+       if (!(info->flags & IEEE80211_TX_CTL_NO_ACK)) {
+@@ -2423,10 +2424,10 @@ static void iwl3945_build_tx_cmd_basic(s
+               tx_flags |= TX_CMD_FLG_SEQ_CTL_MSK;
+       }
+-      if (info->flags & IEEE80211_TX_CTL_USE_RTS_CTS) {
++      if (rc_flags & IEEE80211_TX_RC_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) {
++      } else if (rc_flags & IEEE80211_TX_RC_USE_CTS_PROTECT) {
+               tx_flags &= ~TX_CMD_FLG_RTS_MSK;
+               tx_flags |= TX_CMD_FLG_CTS_MSK;
+       }
+--- a/drivers/net/wireless/mac80211_hwsim.c
++++ b/drivers/net/wireless/mac80211_hwsim.c
+@@ -209,7 +209,7 @@ static bool mac80211_hwsim_tx_frame(stru
+       /* TODO: set mactime */
+       rx_status.freq = data->channel->center_freq;
+       rx_status.band = data->channel->band;
+-      rx_status.rate_idx = info->tx_rate_idx;
++      rx_status.rate_idx = info->control.rates[0].idx;
+       /* TODO: simulate signal strength (and optional packet drop) */
+       /* Copy skb to all enabled radios that are on the current frequency */
+@@ -269,13 +269,9 @@ static int mac80211_hwsim_tx(struct ieee
+       if (txi->control.sta)
+               hwsim_check_sta_magic(txi->control.sta);
+-      memset(&txi->status, 0, sizeof(txi->status));
+-      if (!(txi->flags & IEEE80211_TX_CTL_NO_ACK)) {
+-              if (ack)
+-                      txi->flags |= IEEE80211_TX_STAT_ACK;
+-              else
+-                      txi->status.excessive_retries = 1;
+-      }
++      ieee80211_tx_info_clear_status(txi);
++      if (!(txi->flags & IEEE80211_TX_CTL_NO_ACK) && ack)
++              txi->flags |= IEEE80211_TX_STAT_ACK;
+       ieee80211_tx_status_irqsafe(hw, skb);
+       return NETDEV_TX_OK;
+ }
+--- a/drivers/net/wireless/rtl8180_dev.c
++++ b/drivers/net/wireless/rtl8180_dev.c
+@@ -182,15 +182,13 @@ static void rtl8180_handle_tx(struct iee
+                                skb->len, PCI_DMA_TODEVICE);
+               info = IEEE80211_SKB_CB(skb);
+-              memset(&info->status, 0, sizeof(info->status));
++              ieee80211_tx_info_clear_status(info);
+-              if (!(info->flags & IEEE80211_TX_CTL_NO_ACK)) {
+-                      if (flags & RTL818X_TX_DESC_FLAG_TX_OK)
+-                              info->flags |= IEEE80211_TX_STAT_ACK;
+-                      else
+-                              info->status.excessive_retries = 1;
+-              }
+-              info->status.retry_count = flags & 0xFF;
++              if (!(info->flags & IEEE80211_TX_CTL_NO_ACK) &&
++                  (flags & RTL818X_TX_DESC_FLAG_TX_OK))
++                      info->flags |= IEEE80211_TX_STAT_ACK;
++
++              info->status.rates[0].count = (flags & 0xFF) + 1;
+               ieee80211_tx_status_irqsafe(dev, skb);
+               if (ring->entries - skb_queue_len(&ring->queue) == 2)
+@@ -243,6 +241,7 @@ static int rtl8180_tx(struct ieee80211_h
+       unsigned int idx, prio;
+       dma_addr_t mapping;
+       u32 tx_flags;
++      u8 rc_flags;
+       u16 plcp_len = 0;
+       __le16 rts_duration = 0;
+@@ -261,15 +260,16 @@ static int rtl8180_tx(struct ieee80211_h
+               tx_flags |= RTL818X_TX_DESC_FLAG_DMA |
+                           RTL818X_TX_DESC_FLAG_NO_ENC;
+-      if (info->flags & IEEE80211_TX_CTL_USE_RTS_CTS) {
++      rc_flags = info->control.rates[0].flags;
++      if (rc_flags & IEEE80211_TX_RC_USE_RTS_CTS) {
+               tx_flags |= RTL818X_TX_DESC_FLAG_RTS;
+               tx_flags |= ieee80211_get_rts_cts_rate(dev, info)->hw_value << 19;
+-      } else if (info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT) {
++      } else if (rc_flags & IEEE80211_TX_RC_USE_CTS_PROTECT) {
+               tx_flags |= RTL818X_TX_DESC_FLAG_CTS;
+               tx_flags |= ieee80211_get_rts_cts_rate(dev, info)->hw_value << 19;
+       }
+-      if (info->flags & IEEE80211_TX_CTL_USE_RTS_CTS)
++      if (rc_flags & IEEE80211_TX_RC_USE_RTS_CTS)
+               rts_duration = ieee80211_rts_duration(dev, priv->vif, skb->len,
+                                                     info);
+@@ -292,9 +292,9 @@ static int rtl8180_tx(struct ieee80211_h
+       entry->plcp_len = cpu_to_le16(plcp_len);
+       entry->tx_buf = cpu_to_le32(mapping);
+       entry->frame_len = cpu_to_le32(skb->len);
+-      entry->flags2 = info->control.retries[0].rate_idx >= 0 ?
++      entry->flags2 = info->control.rates[1].idx >= 0 ?
+               ieee80211_get_alt_retry_rate(dev, info, 0)->bitrate << 4 : 0;
+-      entry->retry_limit = info->control.retry_limit;
++      entry->retry_limit = info->control.rates[0].count;
+       entry->flags = cpu_to_le32(tx_flags);
+       __skb_queue_tail(&ring->queue, skb);
+       if (ring->entries - skb_queue_len(&ring->queue) < 2)
+@@ -856,7 +856,7 @@ static int __devinit rtl8180_probe(struc
+       priv = dev->priv;
+       priv->pdev = pdev;
+-      dev->max_altrates = 1;
++      dev->max_rates = 2;
+       SET_IEEE80211_DEV(dev, &pdev->dev);
+       pci_set_drvdata(pdev, dev);
+--- a/drivers/net/wireless/rtl8187_dev.c
++++ b/drivers/net/wireless/rtl8187_dev.c
+@@ -163,7 +163,7 @@ static void rtl8187_tx_cb(struct urb *ur
+       usb_free_urb(info->driver_data[1]);
+       skb_pull(skb, priv->is_rtl8187b ? sizeof(struct rtl8187b_tx_hdr) :
+                                         sizeof(struct rtl8187_tx_hdr));
+-      memset(&info->status, 0, sizeof(info->status));
++      ieee80211_tx_info_clear_status(info);
+       info->flags |= IEEE80211_TX_STAT_ACK;
+       ieee80211_tx_status_irqsafe(hw, skb);
+ }
+@@ -192,12 +192,12 @@ static int rtl8187_tx(struct ieee80211_h
+       flags |= ieee80211_get_tx_rate(dev, info)->hw_value << 24;
+       if (ieee80211_has_morefrags(((struct ieee80211_hdr *)skb->data)->frame_control))
+               flags |= RTL818X_TX_DESC_FLAG_MOREFRAG;
+-      if (info->flags & IEEE80211_TX_CTL_USE_RTS_CTS) {
++      if (info->control.rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS) {
+               flags |= RTL818X_TX_DESC_FLAG_RTS;
+               flags |= ieee80211_get_rts_cts_rate(dev, info)->hw_value << 19;
+               rts_dur = ieee80211_rts_duration(dev, priv->vif,
+                                                skb->len, info);
+-      } else if (info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT) {
++      } else if (info->control.rates[0].flags & IEEE80211_TX_RC_USE_CTS_PROTECT) {
+               flags |= RTL818X_TX_DESC_FLAG_CTS;
+               flags |= ieee80211_get_rts_cts_rate(dev, info)->hw_value << 19;
+       }
+@@ -208,7 +208,7 @@ static int rtl8187_tx(struct ieee80211_h
+               hdr->flags = cpu_to_le32(flags);
+               hdr->len = 0;
+               hdr->rts_duration = rts_dur;
+-              hdr->retry = cpu_to_le32(info->control.retry_limit << 8);
++              hdr->retry = cpu_to_le32((info->control.rates[0].count - 1) << 8);
+               buf = hdr;
+               ep = 2;
+@@ -226,7 +226,7 @@ static int rtl8187_tx(struct ieee80211_h
+               memset(hdr, 0, sizeof(*hdr));
+               hdr->flags = cpu_to_le32(flags);
+               hdr->rts_duration = rts_dur;
+-              hdr->retry = cpu_to_le32(info->control.retry_limit << 8);
++              hdr->retry = cpu_to_le32((info->control.rates[0].count - 1) << 8);
+               hdr->tx_duration =
+                       ieee80211_generic_frame_duration(dev, priv->vif,
+                                                        skb->len, txrate);
+--- a/drivers/net/wireless/p54/p54common.c
++++ b/drivers/net/wireless/p54/p54common.c
+@@ -577,7 +577,7 @@ static void p54_rx_frame_sent(struct iee
+                       __skb_unlink(entry, &priv->tx_queue);
+                       spin_unlock_irqrestore(&priv->tx_queue.lock, flags);
+-                      memset(&info->status, 0, sizeof(info->status));
++                      ieee80211_tx_info_clear_status(info);
+                       entry_hdr = (struct p54_control_hdr *) entry->data;
+                       entry_data = (struct p54_tx_control_allocdata *) entry_hdr->data;
+                       if ((entry_hdr->magic1 & cpu_to_le16(0x4000)) != 0)
+@@ -587,10 +587,8 @@ static void p54_rx_frame_sent(struct iee
+                       if (!(info->flags & IEEE80211_TX_CTL_NO_ACK)) {
+                               if (!(payload->status & 0x01))
+                                       info->flags |= IEEE80211_TX_STAT_ACK;
+-                              else
+-                                      info->status.excessive_retries = 1;
+                       }
+-                      info->status.retry_count = payload->retries - 1;
++                      info->status.rates[0].count = payload->retries;
+                       info->status.ack_signal = p54_rssi_to_dbm(dev,
+                                       le16_to_cpu(payload->ack_rssi));
+                       skb_pull(entry, sizeof(*hdr) + pad + sizeof(*entry_data));
+@@ -816,6 +814,7 @@ static int p54_tx(struct ieee80211_hw *d
+       size_t padding, len;
+       u8 rate;
+       u8 cts_rate = 0x20;
++      u8 rc_flags;
+       current_queue = &priv->tx_stats[skb_get_queue_mapping(skb) + 4];
+       if (unlikely(current_queue->len > current_queue->limit))
+@@ -838,18 +837,19 @@ static int p54_tx(struct ieee80211_hw *d
+               hdr->magic1 = cpu_to_le16(0x0010);
+       hdr->len = cpu_to_le16(len);
+       hdr->type = (info->flags & IEEE80211_TX_CTL_NO_ACK) ? 0 : cpu_to_le16(1);
+-      hdr->retry1 = hdr->retry2 = info->control.retry_limit;
++      hdr->retry1 = hdr->retry2 = info->control.rates[0].count;
+       /* TODO: add support for alternate retry TX rates */
+       rate = ieee80211_get_tx_rate(dev, info)->hw_value;
+-      if (info->flags & IEEE80211_TX_CTL_SHORT_PREAMBLE) {
++      rc_flags = info->control.rates[0].flags;
++      if (rc_flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE) {
+               rate |= 0x10;
+               cts_rate |= 0x10;
+       }
+-      if (info->flags & IEEE80211_TX_CTL_USE_RTS_CTS) {
++      if (rc_flags & IEEE80211_TX_RC_USE_RTS_CTS) {
+               rate |= 0x40;
+               cts_rate |= ieee80211_get_rts_cts_rate(dev, info)->hw_value;
+-      } else if (info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT) {
++      } else if (rc_flags & IEEE80211_TX_RC_USE_CTS_PROTECT) {
+               rate |= 0x20;
+               cts_rate |= ieee80211_get_rts_cts_rate(dev, info)->hw_value;
+       }
+--- a/drivers/net/wireless/iwlwifi/iwl-4965.c
++++ b/drivers/net/wireless/iwlwifi/iwl-4965.c
+@@ -619,10 +619,10 @@ static void iwl4965_gain_computation(str
+ static void iwl4965_rts_tx_cmd_flag(struct ieee80211_tx_info *info,
+                       __le32 *tx_flags)
+ {
+-      if (info->flags & IEEE80211_TX_CTL_USE_RTS_CTS) {
++      if (info->control.rates[0].flags & IEEE80211_TX_RC_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) {
++      } else if (info->control.rates[0].flags & IEEE80211_TX_RC_USE_CTS_PROTECT) {
+               *tx_flags &= ~TX_CMD_FLG_RTS_MSK;
+               *tx_flags |= TX_CMD_FLG_CTS_MSK;
+       }
+@@ -2070,7 +2070,7 @@ static int iwl4965_tx_status_reply_tx(st
+                                  agg->frame_count, agg->start_idx, idx);
+               info = IEEE80211_SKB_CB(priv->txq[txq_id].txb[idx].skb[0]);
+-              info->status.retry_count = tx_resp->failure_frame;
++              info->status.rates[0].count = tx_resp->failure_frame + 1;
+               info->flags &= ~IEEE80211_TX_CTL_AMPDU;
+               info->flags |= iwl_is_tx_success(status)?
+                       IEEE80211_TX_STAT_ACK : 0;
+@@ -2227,7 +2227,7 @@ static void iwl4965_rx_reply_tx(struct i
+                       iwl_txq_check_empty(priv, sta_id, tid, txq_id);
+               }
+       } else {
+-              info->status.retry_count = tx_resp->failure_frame;
++              info->status.rates[0].count = tx_resp->failure_frame + 1;
+               info->flags |=
+                       iwl_is_tx_success(status) ? IEEE80211_TX_STAT_ACK : 0;
+               iwl_hwrate_to_tx_control(priv,
+--- a/drivers/net/wireless/iwlwifi/iwl-5000.c
++++ b/drivers/net/wireless/iwlwifi/iwl-5000.c
+@@ -390,8 +390,8 @@ static void iwl5000_chain_noise_reset(st
+ 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))
++      if ((info->control.rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS) ||
++          (info->control.rates[0].flags & IEEE80211_TX_RC_USE_CTS_PROTECT))
+               *tx_flags |= TX_CMD_FLG_RTS_CTS_MSK;
+       else
+               *tx_flags &= ~TX_CMD_FLG_RTS_CTS_MSK;
+@@ -1136,7 +1136,7 @@ static int iwl5000_tx_status_reply_tx(st
+                                  agg->frame_count, agg->start_idx, idx);
+               info = IEEE80211_SKB_CB(priv->txq[txq_id].txb[idx].skb[0]);
+-              info->status.retry_count = tx_resp->failure_frame;
++              info->status.rates[0].count = tx_resp->failure_frame + 1;
+               info->flags &= ~IEEE80211_TX_CTL_AMPDU;
+               info->flags |= iwl_is_tx_success(status)?
+                       IEEE80211_TX_STAT_ACK : 0;
+@@ -1289,7 +1289,7 @@ static void iwl5000_rx_reply_tx(struct i
+                       iwl_txq_check_empty(priv, sta_id, tid, txq_id);
+               }
+       } else {
+-              info->status.retry_count = tx_resp->failure_frame;
++              info->status.rates[0].count = tx_resp->failure_frame + 1;
+               info->flags =
+                       iwl_is_tx_success(status) ? IEEE80211_TX_STAT_ACK : 0;
+               iwl_hwrate_to_tx_control(priv,
+--- a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c
++++ b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c
+@@ -800,7 +800,7 @@ static void rs_tx_status(void *priv_r, s
+           !(info->flags & IEEE80211_TX_STAT_AMPDU))
+               return;
+-      retries = info->status.retry_count;
++      retries = info->status.rates[0].count + 1;
+       if (retries > 15)
+               retries = 15;
+@@ -832,20 +832,15 @@ static void rs_tx_status(void *priv_r, s
+       if (priv->band == IEEE80211_BAND_5GHZ)
+               rs_index -= IWL_FIRST_OFDM_RATE;
+-      if ((info->tx_rate_idx < 0) ||
+-          (tbl_type.is_SGI ^
+-              !!(info->flags & IEEE80211_TX_CTL_SHORT_GI)) ||
+-          (tbl_type.is_fat ^
+-              !!(info->flags & IEEE80211_TX_CTL_40_MHZ_WIDTH)) ||
+-          (tbl_type.is_dup ^
+-              !!(info->flags & IEEE80211_TX_CTL_DUP_DATA)) ||
+-          (tbl_type.ant_type ^ info->antenna_sel_tx) ||
+-          (!!(tx_rate & RATE_MCS_HT_MSK) ^
+-              !!(info->flags & IEEE80211_TX_CTL_OFDM_HT)) ||
+-          (!!(tx_rate & RATE_MCS_GF_MSK) ^
+-              !!(info->flags & IEEE80211_TX_CTL_GREEN_FIELD)) ||
++      if ((info->status.rates[0].idx < 0) ||
++          (tbl_type.is_SGI != !!(info->status.rates[0].flags & IEEE80211_TX_RC_SHORT_GI)) ||
++          (tbl_type.is_fat != !!(info->status.rates[0].flags & IEEE80211_TX_RC_40_MHZ_WIDTH)) ||
++          (tbl_type.is_dup != !!(info->status.rates[0].flags & IEEE80211_TX_RC_DUP_DATA)) ||
++          (tbl_type.ant_type != info->antenna_sel_tx) ||
++          (!!(tx_rate & RATE_MCS_HT_MSK) != !!(info->status.rates[0].flags & IEEE80211_TX_RC_MCS)) ||
++          (!!(tx_rate & RATE_MCS_GF_MSK) != !!(info->status.rates[0].flags & IEEE80211_TX_RC_GREEN_FIELD)) ||
+           (hw->wiphy->bands[priv->band]->bitrates[rs_index].bitrate !=
+-           hw->wiphy->bands[info->band]->bitrates[info->tx_rate_idx].bitrate)) {
++           hw->wiphy->bands[info->band]->bitrates[info->status.rates[0].idx].bitrate)) {
+               IWL_DEBUG_RATE("initial rate does not match 0x%x\n", tx_rate);
+               goto out;
+       }
+@@ -2103,15 +2098,17 @@ static void rs_initialize_lq(struct iwl_
+       return;
+ }
+-static void rs_get_rate(void *priv_r, struct ieee80211_supported_band *sband,
+-                      struct ieee80211_sta *sta, void *priv_sta,
+-                      struct sk_buff *skb, struct rate_selection *sel)
++static void rs_get_rate(void *priv_r, struct ieee80211_sta *sta, void *priv_sta,
++                      struct ieee80211_tx_rate_control *txrc)
+ {
+       int i;
++      struct sk_buff *skb = txrc->skb;
++      struct ieee80211_supported_band *sband = txrc->sband;
+       struct iwl_priv *priv = (struct iwl_priv *)priv_r;
+       struct ieee80211_conf *conf = &priv->hw->conf;
+       struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
++      struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+       __le16 fc;
+       struct iwl_lq_sta *lq_sta;
+@@ -2122,7 +2119,7 @@ static void rs_get_rate(void *priv_r, st
+       fc = hdr->frame_control;
+       if (!ieee80211_is_data(fc) || is_multicast_ether_addr(hdr->addr1) ||
+           !sta || !priv_sta) {
+-              sel->rate_idx = rate_lowest_index(sband, sta);
++              info->control.rates[0].idx = rate_lowest_index(sband, sta);
+               return;
+       }
+@@ -2149,13 +2146,13 @@ static void rs_get_rate(void *priv_r, st
+       }
+       if ((i < 0) || (i > IWL_RATE_COUNT)) {
+-              sel->rate_idx = rate_lowest_index(sband, sta);
++              info->control.rates[0].idx = rate_lowest_index(sband, sta);
+               return;
+       }
+       if (sband->band == IEEE80211_BAND_5GHZ)
+               i -= IWL_FIRST_OFDM_RATE;
+-      sel->rate_idx = i;
++      info->control.rates[0].idx = i;
+ }
+ static void *rs_alloc_sta(void *priv_rate, struct ieee80211_sta *sta,
diff --git a/package/mac80211/patches/426-minstrel_performance.patch b/package/mac80211/patches/426-minstrel_performance.patch
new file mode 100644 (file)
index 0000000..7b95163
--- /dev/null
@@ -0,0 +1,100 @@
+This patch enhances minstrel's performance for non-MRR setups,
+by preventing it from sampling slower rates with >95% success
+probability and by putting at least 1 non-sample frame between
+several sample frames.
+
+Signed-off-by: Felix Fietkau <nbd@openwrt.org>
+
+--- a/net/mac80211/rc80211_minstrel.c
++++ b/net/mac80211/rc80211_minstrel.c
+@@ -126,7 +126,9 @@ minstrel_update_stats(struct minstrel_pr
+                       mr->adjusted_retry_count = mr->retry_count >> 1;
+                       if (mr->adjusted_retry_count > 2)
+                               mr->adjusted_retry_count = 2;
++                      mr->sample_limit = 4;
+               } else {
++                      mr->sample_limit = -1;
+                       mr->adjusted_retry_count = mr->retry_count;
+               }
+               if (!mr->adjusted_retry_count)
+@@ -265,7 +267,8 @@ minstrel_get_rate(void *priv, struct iee
+                       (mi->sample_count + mi->sample_deferred / 2);
+       /* delta > 0: sampling required */
+-      if (delta > 0) {
++      if ((delta > 0) && (mrr || !mi->prev_sample)) {
++              struct minstrel_rate *msr;
+               if (mi->packet_count >= 10000) {
+                       mi->sample_deferred = 0;
+                       mi->sample_count = 0;
+@@ -284,13 +287,20 @@ minstrel_get_rate(void *priv, struct iee
+               }
+               sample_ndx = minstrel_get_next_sample(mi);
++              msr = &mi->r[sample_ndx];
+               sample = true;
+-              sample_slower = mrr && (mi->r[sample_ndx].perfect_tx_time >
++              sample_slower = mrr && (msr->perfect_tx_time >
+                       mi->r[ndx].perfect_tx_time);
+               if (!sample_slower) {
+-                      ndx = sample_ndx;
+-                      mi->sample_count++;
++                      if (msr->sample_limit != 0) {
++                              ndx = sample_ndx;
++                              mi->sample_count++;
++                              if (msr->sample_limit > 0)
++                                      msr->sample_limit--;
++                      } else {
++                              sample = false;
++                      }
+               } else {
+                       /* Only use IEEE80211_TX_CTL_RATE_CTRL_PROBE to mark
+                        * packets that have the sampling rate deferred to the
+@@ -302,10 +312,20 @@ minstrel_get_rate(void *priv, struct iee
+                       mi->sample_deferred++;
+               }
+       }
++      mi->prev_sample = sample;
++
++      /* If we're not using MRR and the sampling rate already
++       * has a probability of >95%, we shouldn't be attempting
++       * to use it, as this only wastes precious airtime */
++      if (!mrr && sample && (mi->r[ndx].probability > 17100))
++              ndx = mi->max_tp_rate;
++
+       ar[0].idx = mi->r[ndx].rix;
+       ar[0].count = minstrel_get_retry_count(&mi->r[ndx], info);
+       if (!mrr) {
++              if (!sample)
++                      ar[0].count = mp->max_retry;
+               ar[1].idx = mi->lowest_rix;
+               ar[1].count = mp->max_retry;
+               return;
+@@ -401,6 +421,7 @@ minstrel_rate_init(void *priv, struct ie
+               /* calculate maximum number of retransmissions before
+                * fallback (based on maximum segment size) */
++              mr->sample_limit = -1;
+               mr->retry_count = 1;
+               mr->retry_count_cts = 1;
+               mr->retry_count_rtscts = 1;
+--- a/net/mac80211/rc80211_minstrel.h
++++ b/net/mac80211/rc80211_minstrel.h
+@@ -16,6 +16,7 @@ struct minstrel_rate {
+       unsigned int perfect_tx_time;
+       unsigned int ack_time;
++      int sample_limit;
+       unsigned int retry_count;
+       unsigned int retry_count_cts;
+       unsigned int retry_count_rtscts;
+@@ -57,6 +58,7 @@ struct minstrel_sta_info {
+       int n_rates;
+       struct minstrel_rate *r;
++      bool prev_sample;
+       /* sampling table */
+       u8 *sample_table;
This page took 0.224207 seconds and 4 git commands to generate.