Skip to content

Commit bbde467

Browse files
committed
net: macb: fix zero UDPv4 checksum on transmit
The GEM checksum engine writes its raw result into the UDP checksum field, so a UDPv4 checksum that computes to zero goes out as 0x0000. RFC 768 requires: If the computed checksum is zero, it is transmitted as all ones (the equivalent in one's complement arithmetic). An all zero transmitted checksum value means that the transmitter generated no checksum (for debugging or for higher level protocols that don't care). So these packets lose their integrity check and peers treat them as sent without a checksum. Raspberry Pi confirmed in a simulation of the Cadence IP [1] that the engine skips the final substitution exactly for UDP over IPv4. UDPv6 and TCP come out correct. The IP changelog shows no related change, so probably all GEM revisions have the same bug. Clear the checksum offload features for UDPv4 frames in macb_features_check(), the core then completes the checksum in software before handing the frame over. With ip_summed cleared, macb_pad_and_fcs() appends the FCS and the TX_NOCRC descriptor bit keeps the hardware off the frame. TCP and UDPv6 keep the offload. One-step PTP sync packets keep the hardware path because the MAC rewrites their timestamp during transmit, which would invalidate a software checksum. Leave their existing checksum handling unchanged. [1] #7550 (comment) Fixes: 85ff3d8 ("net/macb: add TX checksum offload feature") Signed-off-by: Nicolai Buchwitz <nb@tipi-net.de>
1 parent 2ce9f9d commit bbde467

1 file changed

Lines changed: 12 additions & 0 deletions

File tree

‎drivers/net/ethernet/cadence/macb_main.c‎

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
#include <linux/etherdevice.h>
1616
#include <linux/firmware/xlnx-zynqmp.h>
1717
#include <linux/gpio/consumer.h>
18+
#include <linux/if_vlan.h>
1819
#include <linux/inetdevice.h>
1920
#include <linux/inetdevice.h>
2021
#include <linux/init.h>
@@ -2442,6 +2443,17 @@ static netdev_features_t macb_features_check(struct sk_buff *skb,
24422443
unsigned int nr_frags, f;
24432444
unsigned int hdrlen;
24442445

2446+
/* The GEM skips the RFC 768 substitution of 0xffff for a zero
2447+
* UDPv4 checksum (UDPv6 is handled), have the core complete
2448+
* UDPv4 in software. One-step PTP sync frames keep the hardware
2449+
* path, the MAC rewrites their timestamp in flight.
2450+
*/
2451+
if (skb->ip_summed == CHECKSUM_PARTIAL &&
2452+
vlan_get_protocol(skb) == htons(ETH_P_IP) &&
2453+
skb->csum_offset == offsetof(struct udphdr, check) &&
2454+
!ptp_one_step_sync(skb))
2455+
features &= ~NETIF_F_CSUM_MASK;
2456+
24452457
/* Validate LSO compatibility */
24462458

24472459
/* there is only one buffer or protocol is not UDP */

0 commit comments

Comments
 (0)