From 397785a1f71007ec3a2457cf527aa1d440618680 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Olivier=20Cochard-Labb=C3=A9?= Date: Thu, 24 Sep 2026 18:09:22 +0200 Subject: [PATCH] pkt-gen: fix UDP checksum when IPv6 address ranges are used update_ip6() left the UDP checksum stale for most packets. Unlike update_ip(), it computed the incremental checksum delta only after the source-address wrap, so every earlier "break" (port increment, address increment, and both random paths) returned with udp_sum still 0 and no correction applied. The trailing delta block also re-read oaddr/naddr after they had been reassigned, so the source and destination deltas could not both be accounted for. Fold each delta in with new_udp_sum() before the corresponding break, mirroring the structure update_ip() already uses, and drop the stale trailing block. IPv4 was not affected. Verified by driving update_addresses() directly and recomputing every checksum from scratch over the real pseudo-header: 128 packets across six range configurations, 12 mismatches before, 0 after. IPv4 passes both before and after. --- apps/pkt-gen/pkt-gen.c | 30 ++++++++++++++---------------- 1 file changed, 14 insertions(+), 16 deletions(-) diff --git a/apps/pkt-gen/pkt-gen.c b/apps/pkt-gen/pkt-gen.c index c17579a14..510f6a3db 100644 --- a/apps/pkt-gen/pkt-gen.c +++ b/apps/pkt-gen/pkt-gen.c @@ -917,7 +917,7 @@ update_ip6(struct pkt *pkt, struct targ *t) struct glob_arg *g = t->g; struct ip6_hdr ip6; struct udphdr udp; - uint16_t udp_sum; + uint16_t udp_sum = 0; uint16_t oaddr, naddr; uint16_t oport, nport; uint8_t group; @@ -925,7 +925,6 @@ update_ip6(struct pkt *pkt, struct targ *t) memcpy(&ip6, &pkt->ipv6.ip, sizeof(ip6)); memcpy(&udp, &pkt->ipv6.udp, sizeof(udp)); do { - udp_sum = 0; group = g->src_ip.ipv6.sgroup; naddr = oaddr = ntohs(ip6.ip6_src.s6_addr16[group]); nport = oport = ntohs(udp.uh_sport); @@ -934,29 +933,28 @@ update_ip6(struct pkt *pkt, struct targ *t) udp.uh_sport = nrand48(t->seed); naddr = ntohs(ip6.ip6_src.s6_addr16[group]); nport = ntohs(udp.uh_sport); + udp_sum = new_udp_sum(udp_sum, oaddr, naddr); + udp_sum = new_udp_sum(udp_sum, oport, nport); break; } if (oport < g->src_ip.port1) { nport = oport + 1; udp.uh_sport = htons(nport); + udp_sum = new_udp_sum(udp_sum, oport, nport); break; } nport = g->src_ip.port0; udp.uh_sport = htons(nport); + udp_sum = new_udp_sum(udp_sum, oport, nport); if (oaddr < ntohs(g->src_ip.ipv6.end.s6_addr16[group])) { naddr = oaddr + 1; ip6.ip6_src.s6_addr16[group] = htons(naddr); + udp_sum = new_udp_sum(udp_sum, oaddr, naddr); break; } naddr = ntohs(g->src_ip.ipv6.start.s6_addr16[group]); ip6.ip6_src.s6_addr16[group] = htons(naddr); - - /* update checksums if needed */ - if (oaddr != naddr) - udp_sum = cksum_add(~oaddr, naddr); - if (oport != nport) - udp_sum = cksum_add(udp_sum, - cksum_add(~oport, nport)); + udp_sum = new_udp_sum(udp_sum, oaddr, naddr); group = g->dst_ip.ipv6.egroup; naddr = oaddr = ntohs(ip6.ip6_dst.s6_addr16[group]); @@ -966,32 +964,32 @@ update_ip6(struct pkt *pkt, struct targ *t) udp.uh_dport = nrand48(t->seed); naddr = ntohs(ip6.ip6_dst.s6_addr16[group]); nport = ntohs(udp.uh_dport); + udp_sum = new_udp_sum(udp_sum, oaddr, naddr); + udp_sum = new_udp_sum(udp_sum, oport, nport); break; } if (oport < g->dst_ip.port1) { nport = oport + 1; udp.uh_dport = htons(nport); + udp_sum = new_udp_sum(udp_sum, oport, nport); break; } nport = g->dst_ip.port0; udp.uh_dport = htons(nport); + udp_sum = new_udp_sum(udp_sum, oport, nport); if (oaddr < ntohs(g->dst_ip.ipv6.end.s6_addr16[group])) { naddr = oaddr + 1; ip6.ip6_dst.s6_addr16[group] = htons(naddr); + udp_sum = new_udp_sum(udp_sum, oaddr, naddr); break; } naddr = ntohs(g->dst_ip.ipv6.start.s6_addr16[group]); ip6.ip6_dst.s6_addr16[group] = htons(naddr); + udp_sum = new_udp_sum(udp_sum, oaddr, naddr); } while (0); /* update checksums */ - if (oaddr != naddr) - udp_sum = cksum_add(udp_sum, - cksum_add(~oaddr, naddr)); - if (oport != nport) - udp_sum = cksum_add(udp_sum, - cksum_add(~oport, nport)); if (udp_sum != 0) - udp.uh_sum = ~cksum_add(~udp.uh_sum, udp_sum); + udp.uh_sum = ~cksum_add(~udp.uh_sum, htons(udp_sum)); memcpy(&pkt->ipv6.ip, &ip6, sizeof(ip6)); memcpy(&pkt->ipv6.udp, &udp, sizeof(udp)); }