[PATCH iwl-net v2] e1000e: fix Tx descriptor field wrapping
flat view
HOTtoday
From: Matt Vollrath <hidden>
Date: 2026-10-28 17:02:59
Also in:
intel-wired-lan, stable
Subsystem:
intel ethernet drivers, networking drivers, the rest · Maintainers:
Tony Nguyen, Przemek Kitszel, Andrew Lunn, "David S. Miller", Eric Dumazet, Jakub Kicinski, Paolo Abeni, Linus Torvalds
When an skb arrives at the driver and the header length exceeds the u8
hdr_len, tucss and tucso fields in e1000_context_desc, wrapped values
are sent to the card. If TSO is enabled, some header lengths will cause
the card to hang.
This was reproduced on an I218-V with an unprivileged Python script.
Fix it by disabling GSO and checksum offload when the header length (and
checksum offset) would exceed the field widths. Compensate for a
software-inserted VLAN tag.
Because of a quirk in the ordering of ndo_features_check, the skb's
transport_header field may be stale. If the skb carries
CHECKSUM_PARTIAL, use csum_start to find the header. Otherwise, there's
no reliable interface, so don't offload it.
Fixes: bc7f75fa9788 ("[E1000E]: New pci-express e1000 driver (currently for ICH9 devices only)")
Cc: <redacted>
Assisted-by: LLM
Signed-off-by: Matt Vollrath <redacted>
---
drivers/net/ethernet/intel/e1000e/netdev.c | 34 +++++++++++++++++++++-
1 file changed, 33 insertions(+), 1 deletion(-)
diff --git a/drivers/net/ethernet/intel/e1000e/netdev.c b/drivers/net/ethernet/intel/e1000e/netdev.c
index 6f85dab5c55c5..370776657d100 100644
--- a/drivers/net/ethernet/intel/e1000e/netdev.c
+++ b/drivers/net/ethernet/intel/e1000e/netdev.c@@ -7355,6 +7355,38 @@ static int e1000_set_features(struct net_device *netdev, return 1; } +static netdev_features_t e1000_features_check(struct sk_buff *skb, + struct net_device *netdev, + netdev_features_t features) +{ + /* Do not offload packets whose header lengths exceed the u8 fields + * in the descriptor. + */ + unsigned int hdr_len = 0; + + if (skb->ip_summed == CHECKSUM_PARTIAL) { + const struct tcphdr *th = (const void *)skb_checksum_start(skb); + + hdr_len = skb_checksum_start_offset(skb); + if (skb_is_gso(skb) && skb_is_gso_tcp(skb)) + hdr_len += __tcp_hdrlen(th); + else + hdr_len += skb->csum_offset; + } else if (skb_is_gso(skb)) { + /* Work around untrustworthy header offsets in this case. */ + return features & ~(NETIF_F_CSUM_MASK | NETIF_F_GSO_MASK); + } + + if (skb_vlan_tag_present(skb) && + !vlan_hw_offload_capable(features, skb->vlan_proto)) + hdr_len += VLAN_HLEN; + + if (hdr_len > U8_MAX) + features &= ~(NETIF_F_CSUM_MASK | NETIF_F_GSO_MASK); + + return features; +} + static const struct net_device_ops e1000e_netdev_ops = { .ndo_open = e1000e_open, .ndo_stop = e1000e_close,
@@ -7374,7 +7406,7 @@ static const struct net_device_ops e1000e_netdev_ops = { #endif .ndo_set_features = e1000_set_features, .ndo_fix_features = e1000_fix_features, - .ndo_features_check = passthru_features_check, + .ndo_features_check = e1000_features_check, .ndo_hwtstamp_get = e1000e_hwtstamp_get, .ndo_hwtstamp_set = e1000e_hwtstamp_set, };
base-commit: 7076f684d5132e6a6145e1da2fa74771ecd052e5 -- 2.43.0