igc_request_tx_tstamp() takes an extra skb reference before transmit preparation. For GSO packets, igc_tso() calls skb_cow_head(), which can reach pskb_expand_head() with a shared skb when the header is cloned. Commit c7d8bc3dd511 ("net: skbuff: don't BUG() on bad arguments to pskb_expand_head()") replaced the BUG_ON() with -EINVAL, causing TSO preparation to fail and the packet to be dropped. For non-GSO packets with CHECKSUM_PARTIAL, igc_tx_csum() falls back to skb_checksum_help() for unsupported checksum offsets. This can also reach pskb_expand_head() through skb_ensure_writable(). igc_tx_csum() ignores the error, allowing transmission to continue without completing the checksum. Move TSO and checksum preparation before TX timestamp reservation so the extra skb reference cannot interfere with either operation. Fixes: 2c344ae24501 ("igc: Add support for TX timestamping") Fixes: f38b782dccab ("igc: Add support for TSO") Signed-off-by: Paul Moses
--- drivers/net/ethernet/intel/igc/igc_main.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/net/ethernet/intel/igc/igc_main.c b/drivers/net/ethernet/intel/igc/igc_main.c index f1bf4e462a51..cd4c9815fca7 100644 --- a/drivers/net/ethernet/intel/igc/igc_main.c +++ b/drivers/net/ethernet/intel/igc/igc_main.c @@ -1678,6 +1678,12 @@ static netdev_tx_t igc_xmit_frame_ring(struct sk_buff *skb, goto out_drop; } + tso = igc_tso(tx_ring, first, launch_time, first_flag, &hdr_len); + if (tso < 0) + goto out_drop; + else if (!tso) + igc_tx_csum(tx_ring, first, launch_time, first_flag); + if (unlikely(test_bit(IGC_RING_FLAG_TX_HWTSTAMP, &tx_ring->flags) && skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP)) { unsigned long flags; @@ -1697,12 +1703,6 @@ static netdev_tx_t igc_xmit_frame_ring(struct sk_buff *skb, spin_unlock_irqrestore(&adapter->ptp_tx_lock, flags); } - tso = igc_tso(tx_ring, first, launch_time, first_flag, &hdr_len); - if (tso < 0) - goto out_drop; - else if (!tso) - igc_tx_csum(tx_ring, first, launch_time, first_flag); - igc_tx_map(tx_ring, first, hdr_len); return NETDEV_TX_OK;