diff options
author | Felix Fietkau <nbd@openwrt.org> | 2012-06-15 05:04:53 +0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2012-06-19 22:56:24 +0400 |
commit | 80b08a8d8829a58b5db14b1417151094cc28face (patch) | |
tree | 69a5f0c17529b1c3fda8344a65a7a6de86754264 /drivers/net/wireless | |
parent | 76591bea9714a58d8924154068c78d702eb2cb17 (diff) | |
download | linux-80b08a8d8829a58b5db14b1417151094cc28face.tar.xz |
ath9k: fix invalid pointer access in the tx path
After setup_frame_info has been called, only info->control.rates is still
valid, other control fields have been overwritten by the ath_frame_info
data. Move the access to info->control.vif for checking short preamble
to setup_frame_info before it gets overwritten.
This regression was introduced in commit d47a61aa
"ath9k: Fix multi-VIF BSS handling"
Signed-off-by: Felix Fietkau <nbd@openwrt.org>
Reported-by: Thomas Hühn <thomas@net.t-labs.tu-berlin.de>
Acked-by: Sujith Manoharan <c_manoha@qca.qualcomm.com>
Cc: stable@vger.kernel.org [3.4]
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless')
-rw-r--r-- | drivers/net/wireless/ath/ath9k/ath9k.h | 1 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath9k/xmit.c | 29 |
2 files changed, 18 insertions, 12 deletions
diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index a277cf6f339d..4866550ddd96 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -214,6 +214,7 @@ struct ath_frame_info { enum ath9k_key_type keytype; u8 keyix; u8 retries; + u8 rtscts_rate; }; struct ath_buf_state { diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index efb7f00f3561..4d571394c7a8 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c @@ -938,6 +938,7 @@ static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf, struct ieee80211_tx_rate *rates; const struct ieee80211_rate *rate; struct ieee80211_hdr *hdr; + struct ath_frame_info *fi = get_frame_info(bf->bf_mpdu); int i; u8 rix = 0; @@ -948,18 +949,7 @@ static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf, /* set dur_update_en for l-sig computation except for PS-Poll frames */ info->dur_update = !ieee80211_is_pspoll(hdr->frame_control); - - /* - * We check if Short Preamble is needed for the CTS rate by - * checking the BSS's global flag. - * But for the rate series, IEEE80211_TX_RC_USE_SHORT_PREAMBLE is used. - */ - rate = ieee80211_get_rts_cts_rate(sc->hw, tx_info); - info->rtscts_rate = rate->hw_value; - - if (tx_info->control.vif && - tx_info->control.vif->bss_conf.use_short_preamble) - info->rtscts_rate |= rate->hw_value_short; + info->rtscts_rate = fi->rtscts_rate; for (i = 0; i < 4; i++) { bool is_40, is_sgi, is_sp; @@ -1776,10 +1766,22 @@ static void setup_frame_info(struct ieee80211_hw *hw, struct sk_buff *skb, struct ieee80211_sta *sta = tx_info->control.sta; struct ieee80211_key_conf *hw_key = tx_info->control.hw_key; struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; + const struct ieee80211_rate *rate; struct ath_frame_info *fi = get_frame_info(skb); struct ath_node *an = NULL; enum ath9k_key_type keytype; + bool short_preamble = false; + + /* + * We check if Short Preamble is needed for the CTS rate by + * checking the BSS's global flag. + * But for the rate series, IEEE80211_TX_RC_USE_SHORT_PREAMBLE is used. + */ + if (tx_info->control.vif && + tx_info->control.vif->bss_conf.use_short_preamble) + short_preamble = true; + rate = ieee80211_get_rts_cts_rate(hw, tx_info); keytype = ath9k_cmn_get_hw_crypto_keytype(skb); if (sta) @@ -1794,6 +1796,9 @@ static void setup_frame_info(struct ieee80211_hw *hw, struct sk_buff *skb, fi->keyix = ATH9K_TXKEYIX_INVALID; fi->keytype = keytype; fi->framelen = framelen; + fi->rtscts_rate = rate->hw_value; + if (short_preamble) + fi->rtscts_rate |= rate->hw_value_short; } u8 ath_txchainmask_reduction(struct ath_softc *sc, u8 chainmask, u32 rate) |