Commit bdc71bc5 authored by Bob Copeland's avatar Bob Copeland Committed by John W. Linville

ath5k: fix error handling in ath5k_beacon_send

This cleans up error handling for the beacon in case of dma mapping
failure.  We need to free the skb when dma mapping fails instead of
nulling and leaking the pointer, and we should bail out to avoid
giving the hardware the bad descriptor.

Finally, we need to perform the null check after trying to update
the beacon, or else beacons will never be sent after a single
mapping failure.

Cc: stable@kernel.org
Signed-off-by: default avatarBob Copeland <me@bobcopeland.com>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent 276b02e2
...@@ -1735,6 +1735,8 @@ ath5k_beacon_setup(struct ath5k_hw *ah, struct ath5k_buf *bf) ...@@ -1735,6 +1735,8 @@ ath5k_beacon_setup(struct ath5k_hw *ah, struct ath5k_buf *bf)
if (dma_mapping_error(ah->dev, bf->skbaddr)) { if (dma_mapping_error(ah->dev, bf->skbaddr)) {
ATH5K_ERR(ah, "beacon DMA mapping failed\n"); ATH5K_ERR(ah, "beacon DMA mapping failed\n");
dev_kfree_skb_any(skb);
bf->skb = NULL;
return -EIO; return -EIO;
} }
...@@ -1819,8 +1821,6 @@ ath5k_beacon_update(struct ieee80211_hw *hw, struct ieee80211_vif *vif) ...@@ -1819,8 +1821,6 @@ ath5k_beacon_update(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
ath5k_txbuf_free_skb(ah, avf->bbuf); ath5k_txbuf_free_skb(ah, avf->bbuf);
avf->bbuf->skb = skb; avf->bbuf->skb = skb;
ret = ath5k_beacon_setup(ah, avf->bbuf); ret = ath5k_beacon_setup(ah, avf->bbuf);
if (ret)
avf->bbuf->skb = NULL;
out: out:
return ret; return ret;
} }
...@@ -1840,6 +1840,7 @@ ath5k_beacon_send(struct ath5k_hw *ah) ...@@ -1840,6 +1840,7 @@ ath5k_beacon_send(struct ath5k_hw *ah)
struct ath5k_vif *avf; struct ath5k_vif *avf;
struct ath5k_buf *bf; struct ath5k_buf *bf;
struct sk_buff *skb; struct sk_buff *skb;
int err;
ATH5K_DBG_UNLIMIT(ah, ATH5K_DEBUG_BEACON, "in beacon_send\n"); ATH5K_DBG_UNLIMIT(ah, ATH5K_DEBUG_BEACON, "in beacon_send\n");
...@@ -1888,11 +1889,6 @@ ath5k_beacon_send(struct ath5k_hw *ah) ...@@ -1888,11 +1889,6 @@ ath5k_beacon_send(struct ath5k_hw *ah)
avf = (void *)vif->drv_priv; avf = (void *)vif->drv_priv;
bf = avf->bbuf; bf = avf->bbuf;
if (unlikely(bf->skb == NULL || ah->opmode == NL80211_IFTYPE_STATION ||
ah->opmode == NL80211_IFTYPE_MONITOR)) {
ATH5K_WARN(ah, "bf=%p bf_skb=%p\n", bf, bf ? bf->skb : NULL);
return;
}
/* /*
* Stop any current dma and put the new frame on the queue. * Stop any current dma and put the new frame on the queue.
...@@ -1906,8 +1902,17 @@ ath5k_beacon_send(struct ath5k_hw *ah) ...@@ -1906,8 +1902,17 @@ ath5k_beacon_send(struct ath5k_hw *ah)
/* refresh the beacon for AP or MESH mode */ /* refresh the beacon for AP or MESH mode */
if (ah->opmode == NL80211_IFTYPE_AP || if (ah->opmode == NL80211_IFTYPE_AP ||
ah->opmode == NL80211_IFTYPE_MESH_POINT) ah->opmode == NL80211_IFTYPE_MESH_POINT) {
ath5k_beacon_update(ah->hw, vif); err = ath5k_beacon_update(ah->hw, vif);
if (err)
return;
}
if (unlikely(bf->skb == NULL || ah->opmode == NL80211_IFTYPE_STATION ||
ah->opmode == NL80211_IFTYPE_MONITOR)) {
ATH5K_WARN(ah, "bf=%p bf_skb=%p\n", bf, bf->skb);
return;
}
trace_ath5k_tx(ah, bf->skb, &ah->txqs[ah->bhalq]); trace_ath5k_tx(ah, bf->skb, &ah->txqs[ah->bhalq]);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment