summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHelmut Schaa <helmut.schaa@googlemail.com>2013-08-16 21:39:40 +0200
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2013-09-07 21:58:15 -0700
commit837049ab21626553f6d84062cde74e38d4b7b0bd (patch)
treee2ef18f41517b33119cc4a0a7e5b6a0f806e5b37
parent52b331e9991f5639e8888349eccc02dd2986b51c (diff)
downloadlinux-stable-837049ab21626553f6d84062cde74e38d4b7b0bd.tar.gz
linux-stable-837049ab21626553f6d84062cde74e38d4b7b0bd.tar.bz2
linux-stable-837049ab21626553f6d84062cde74e38d4b7b0bd.zip
ath9k_htc: Restore skb headroom when returning skb to mac80211
commit d2e9fc141e2aa21f4b35ee27072d84e9aa6e2ba0 upstream. ath9k_htc adds padding between the 802.11 header and the payload during TX by moving the header. When handing the frame back to mac80211 for TX status handling the header is not moved back into its original position. This can result in a too small skb headroom when entering ath9k_htc again (due to a soft retransmission for example) causing an skb_under_panic oops. Fix this by moving the 802.11 header back into its original position before returning the frame to mac80211 as other drivers like rt2x00 or ath5k do. Reported-by: Marc Kleine-Budde <mkl@blackshift.org> Signed-off-by: Helmut Schaa <helmut.schaa@googlemail.com> Tested-by: Marc Kleine-Budde <mkl@blackshift.org> Signed-off-by: Marc Kleine-Budde <mkl@blackshift.org> Signed-off-by: John W. Linville <linville@tuxdriver.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r--drivers/net/wireless/ath/ath9k/htc_drv_txrx.c10
1 files changed, 10 insertions, 0 deletions
diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c b/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c
index 3e40a6461512..b290a8ecfdbc 100644
--- a/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c
+++ b/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c
@@ -448,6 +448,7 @@ static void ath9k_htc_tx_process(struct ath9k_htc_priv *priv,
struct ieee80211_conf *cur_conf = &priv->hw->conf;
bool txok;
int slot;
+ int hdrlen, padsize;
slot = strip_drv_header(priv, skb);
if (slot < 0) {
@@ -504,6 +505,15 @@ send_mac80211:
ath9k_htc_tx_clear_slot(priv, slot);
+ /* Remove padding before handing frame back to mac80211 */
+ hdrlen = ieee80211_get_hdrlen_from_skb(skb);
+
+ padsize = hdrlen & 3;
+ if (padsize && skb->len > hdrlen + padsize) {
+ memmove(skb->data + padsize, skb->data, hdrlen);
+ skb_pull(skb, padsize);
+ }
+
/* Send status to mac80211 */
ieee80211_tx_status(priv->hw, skb);
}