diff options
author | nbd <nbd@3c298f89-4303-0410-b956-a3cf2f4a3e73> | 2008-10-11 01:33:09 +0000 |
---|---|---|
committer | nbd <nbd@3c298f89-4303-0410-b956-a3cf2f4a3e73> | 2008-10-11 01:33:09 +0000 |
commit | 090f16f6fb1019af891be04e2da176f6feb65cc9 (patch) | |
tree | 1fafd2be3f6989795ec69425f3dabbade11138b2 /package/mac80211 | |
parent | 042b8de61d833ef841b2ccf4d39f673aecaacd3a (diff) |
mac80211: add rate control rewrite and enhance the performance of the minstrel algorithm for non-mrr configurations
git-svn-id: svn://svn.openwrt.org/openwrt/trunk@12948 3c298f89-4303-0410-b956-a3cf2f4a3e73
Diffstat (limited to 'package/mac80211')
22 files changed, 7636 insertions, 129 deletions
diff --git a/package/mac80211/patches/300-minstrel_no_mrr.patch b/package/mac80211/patches/300-minstrel_no_mrr.patch deleted file mode 100644 index d4c04c4d8b..0000000000 --- a/package/mac80211/patches/300-minstrel_no_mrr.patch +++ /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 index db731e584a..0000000000 --- a/package/mac80211/patches/310-b43_txstatus.patch +++ /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 index 0000000000..4dbdba998b --- /dev/null +++ b/package/mac80211/patches/407-debugfs-sta-work-fix.patch @@ -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 index 0000000000..5cbab6889a --- /dev/null +++ b/package/mac80211/patches/408-mac80211-remove-agg-debugfs.patch @@ -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 index 0000000000..77c4701495 --- /dev/null +++ b/package/mac80211/patches/409-mac80211-remove-mesh-debugfs.patch @@ -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 index 0000000000..bd66d04a9d --- /dev/null +++ b/package/mac80211/patches/410-mac80211-cleanups.patch @@ -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 index 0000000000..c8a1a225b6 --- /dev/null +++ b/package/mac80211/patches/411-mac80211-remove-wiphy-to-hw.patch @@ -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 index 0000000000..f18569b936 --- /dev/null +++ b/package/mac80211/patches/412-mac80211-warn-ieee80211_hw_config-failure.patch @@ -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 index 0000000000..a7d8a9534a --- /dev/null +++ b/package/mac80211/patches/413-mac80211-remove-antgain-cfg.patch @@ -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 index 0000000000..145e273e5b --- /dev/null +++ b/package/mac80211/patches/414-mac80211-slot-time.patch @@ -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 index 0000000000..114c94390b --- /dev/null +++ b/package/mac80211/patches/415-mac80211-fix-exploit.patch @@ -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 index 0000000000..aee45825ea --- /dev/null +++ b/package/mac80211/patches/416-mac80211-fix-netdev-notifier.patch @@ -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 index 0000000000..3cfab61325 --- /dev/null +++ b/package/mac80211/patches/417-cfg80211-fix-rename.patch @@ -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 index 0000000000..61ae15a885 --- /dev/null +++ b/package/mac80211/patches/418-ieee80211-cleanup-ht-terminology.patch @@ -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 index 0000000000..dbdd64aa23 --- /dev/null +++ b/package/mac80211/patches/419-mac80211-remove-antenna-sel.patch @@ -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 index 0000000000..4bae8cbb59 --- /dev/null +++ b/package/mac80211/patches/420-mac80211-hw-conf-change-flags.patch @@ -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 index 0000000000..d6f6b5a589 --- /dev/null +++ b/package/mac80211/patches/421-nl80211-export-ht.patch @@ -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 index 0000000000..72fbd9cb70 --- /dev/null +++ b/package/mac80211/patches/422-mac80211-seqno-station.patch @@ -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 index 0000000000..556d651a0a --- /dev/null +++ b/package/mac80211/patches/423-mac80211-make-bss-conf-part-of-vif.patch @@ -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 index 0000000000..084ed9a132 --- /dev/null +++ b/package/mac80211/patches/424-mac80211-make-retry-limits-available.patch @@ -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 index 0000000000..c0652a0b0d --- /dev/null +++ b/package/mac80211/patches/425-rewrite-rate-api.patch @@ -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 index 0000000000..7b95163c6c --- /dev/null +++ b/package/mac80211/patches/426-minstrel_performance.patch @@ -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; |