In stmmac_xmit(), when the DMA mapping of the linear part or of a fragment fails, the error path only frees the skb. This leaves behind the DMA mappings already created for the linear part and for the fragments mapped before the failure, which are never unmapped. The VLAN context descriptor programmed by stmmac_vlan_insert() is also left behind with its OWN bit set while tx_q->cur_tx has been advanced past it, so the DMA engine later consumes the orphaned descriptor and applies its stale VLAN tag to an unrelated frame. Release the descriptors and their DMA mappings in the dma_map_err path with stmmac_release_tx_desc() and stmmac_free_tx_buffer(), walking from first_entry to entry, then roll back tx_q->cur_tx and release the VLAN context descriptor. Fixes: 30d932279dc2 ("net: stmmac: Add support for VLAN Insertion Offload") Signed-off-by: ZhaoJinming --- drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 29 +++++++++++++++++++---- 1 file changed, 25 insertions(+), 4 deletions(-) diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c index 24656b35350b14454fb10deced6516eb89e2c0c9..2e36c27e2cfb436af3566cf1c3e70d32ce9830a0 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c @@ -4769,12 +4769,12 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev) unsigned int nopaged_len = skb_headlen(skb); u32 queue = skb_get_queue_mapping(skb); int nfrags = skb_shinfo(skb)->nr_frags; - unsigned int first_entry, tx_packets; + unsigned int first_entry, entry, tx_packets; struct stmmac_txq_stats *txq_stats; struct dma_desc *desc, *first_desc; struct stmmac_tx_queue *tx_q; int i, csum_insertion = 0; - int entry, first_tx; + int first_tx, ret; dma_addr_t dma_addr; u32 sdu_len; @@ -4832,9 +4832,10 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev) csum_insertion = skb->ip_summed == CHECKSUM_PARTIAL; if (unlikely(is_jumbo)) { - entry = stmmac_jumbo_frm(priv, tx_q, skb, csum_insertion); - if (unlikely(entry < 0) && (entry != -EINVAL)) + ret = stmmac_jumbo_frm(priv, tx_q, skb, csum_insertion); + if (unlikely(ret < 0) && (ret != -EINVAL)) goto dma_map_err; + entry = ret; } else { bool last_segment = (nfrags == 0); @@ -4984,6 +4985,26 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev) dma_map_err: netdev_err(priv->dev, "Tx DMA map failed\n"); + + /* entry points one past the last descriptor written for this frame: + * on failure it is the descriptor whose DMA mapping failed, so walk + * from first_entry up to, but not including, entry. Reset cur_tx + * unconditionally as both stmmac_vlan_insert() and stmmac_jumbo_frm() + * may have advanced it, and release the VLAN context descriptor. + */ + while (first_entry != entry) { + desc = stmmac_get_tx_desc(priv, tx_q, first_entry); + stmmac_release_tx_desc(priv, desc, priv->descriptor_mode); + stmmac_free_tx_buffer(priv, &priv->dma_conf, queue, first_entry); + first_entry = STMMAC_NEXT_ENTRY(first_entry, + priv->dma_conf.dma_tx_size); + } + + tx_q->cur_tx = first_tx; + if (has_vlan) { + desc = stmmac_get_tx_desc(priv, tx_q, first_tx); + stmmac_release_tx_desc(priv, desc, priv->descriptor_mode); + } max_sdu_err: dev_kfree_skb(skb); priv->xstats.tx_dropped++; --- base-commit: 893e11787f78e43b534e252249ac3fff4d1333f8 change-id: 20260909-stmmac-fix-vlan-desc-leak-f057bb061daa Best regards, -- ZhaoJinming