wcn36xx: don't keep reference to skb if transmission failed
When wcn36xx_dxe_tx_frame() fails to transmit the TX frame, the driver will call into ieee80211_free_txskb() for the skb in flight, so it'll no longer be valid. Hence, we shouldn't keep a reference to it in ctl->skb. Also, if the skb has IEEE80211_TX_CTL_REQ_TX_STATUS set, a pointer to it will currently remain in wcn->tx_ack_skb, which will potentially lead to a crash if accessed later. Fix this by checking the return value of wcn36xx_dxe_tx_frame(), and nullify wcn->tx_ack_skb again in case of errors. Move the assignment of ctl->skb in wcn36xx_dxe_tx_frame() so it only happens when the transmission is successful. Signed-off-by: Daniel Mack <daniel@zonque.org> Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
This commit is contained in:
parent
7cae35199b
commit
271f1e65ff
@ -693,7 +693,6 @@ int wcn36xx_dxe_tx_frame(struct wcn36xx *wcn,
|
|||||||
|
|
||||||
/* Set source address of the SKB we send */
|
/* Set source address of the SKB we send */
|
||||||
ctl = ctl->next;
|
ctl = ctl->next;
|
||||||
ctl->skb = skb;
|
|
||||||
desc = ctl->desc;
|
desc = ctl->desc;
|
||||||
if (ctl->bd_cpu_addr) {
|
if (ctl->bd_cpu_addr) {
|
||||||
wcn36xx_err("bd_cpu_addr cannot be NULL for skb DXE\n");
|
wcn36xx_err("bd_cpu_addr cannot be NULL for skb DXE\n");
|
||||||
@ -702,8 +701,8 @@ int wcn36xx_dxe_tx_frame(struct wcn36xx *wcn,
|
|||||||
}
|
}
|
||||||
|
|
||||||
desc->src_addr_l = dma_map_single(wcn->dev,
|
desc->src_addr_l = dma_map_single(wcn->dev,
|
||||||
ctl->skb->data,
|
skb->data,
|
||||||
ctl->skb->len,
|
skb->len,
|
||||||
DMA_TO_DEVICE);
|
DMA_TO_DEVICE);
|
||||||
if (dma_mapping_error(wcn->dev, desc->src_addr_l)) {
|
if (dma_mapping_error(wcn->dev, desc->src_addr_l)) {
|
||||||
dev_err(wcn->dev, "unable to DMA map src_addr_l\n");
|
dev_err(wcn->dev, "unable to DMA map src_addr_l\n");
|
||||||
@ -711,6 +710,7 @@ int wcn36xx_dxe_tx_frame(struct wcn36xx *wcn,
|
|||||||
goto unlock;
|
goto unlock;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ctl->skb = skb;
|
||||||
desc->dst_addr_l = ch->dxe_wq;
|
desc->dst_addr_l = ch->dxe_wq;
|
||||||
desc->fr_len = ctl->skb->len;
|
desc->fr_len = ctl->skb->len;
|
||||||
|
|
||||||
|
@ -273,6 +273,7 @@ int wcn36xx_start_tx(struct wcn36xx *wcn,
|
|||||||
bool bcast = is_broadcast_ether_addr(hdr->addr1) ||
|
bool bcast = is_broadcast_ether_addr(hdr->addr1) ||
|
||||||
is_multicast_ether_addr(hdr->addr1);
|
is_multicast_ether_addr(hdr->addr1);
|
||||||
struct wcn36xx_tx_bd bd;
|
struct wcn36xx_tx_bd bd;
|
||||||
|
int ret;
|
||||||
|
|
||||||
memset(&bd, 0, sizeof(bd));
|
memset(&bd, 0, sizeof(bd));
|
||||||
|
|
||||||
@ -317,5 +318,17 @@ int wcn36xx_start_tx(struct wcn36xx *wcn,
|
|||||||
buff_to_be((u32 *)&bd, sizeof(bd)/sizeof(u32));
|
buff_to_be((u32 *)&bd, sizeof(bd)/sizeof(u32));
|
||||||
bd.tx_bd_sign = 0xbdbdbdbd;
|
bd.tx_bd_sign = 0xbdbdbdbd;
|
||||||
|
|
||||||
return wcn36xx_dxe_tx_frame(wcn, vif_priv, &bd, skb, is_low);
|
ret = wcn36xx_dxe_tx_frame(wcn, vif_priv, &bd, skb, is_low);
|
||||||
|
if (ret && bd.tx_comp) {
|
||||||
|
/* If the skb has not been transmitted,
|
||||||
|
* don't keep a reference to it.
|
||||||
|
*/
|
||||||
|
spin_lock_irqsave(&wcn->dxe_lock, flags);
|
||||||
|
wcn->tx_ack_skb = NULL;
|
||||||
|
spin_unlock_irqrestore(&wcn->dxe_lock, flags);
|
||||||
|
|
||||||
|
ieee80211_wake_queues(wcn->hw);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user