The TCP and UDP checksums are computed using the data in the TCP/UDP
payload but also some informations in the IP header (protocol,
length, source and destination addresses).
We add two functions, proto_ipv4_header_checksum() and
proto_ipv6_header_checksum(), to compute the checksum of the IP
header part.
Signed-off-by: Laurent Vivier
---
ip.h | 24 ++++++++++++++++++++++++
tcp.c | 40 +++++++++++++++-------------------------
udp.c | 6 ++----
3 files changed, 41 insertions(+), 29 deletions(-)
diff --git a/ip.h b/ip.h
index ff7902c45a95..87cb8dd21d2e 100644
--- a/ip.h
+++ b/ip.h
@@ -97,4 +97,28 @@ static inline uint16_t ipv4_hdr_checksum(struct iphdr *iph, int proto)
return ~csum_fold(sum);
}
+
+static inline uint32_t proto_ipv4_header_checksum(struct iphdr *iph, int proto)
+{
+ uint32_t sum = htons(proto);
+
+ sum += (iph->saddr >> 16) & 0xffff;
+ sum += iph->saddr & 0xffff;
+ sum += (iph->daddr >> 16) & 0xffff;
+ sum += iph->daddr & 0xffff;
+ sum += htons(ntohs(iph->tot_len) - 20);
+
+ return sum;
+}
+
+static inline uint32_t proto_ipv6_header_checksum(struct ipv6hdr *ip6h,
+ int proto)
+{
+ uint32_t sum = htons(proto) + ip6h->payload_len;
+
+ sum += sum_16b(&ip6h->saddr, sizeof(ip6h->saddr));
+ sum += sum_16b(&ip6h->daddr, sizeof(ip6h->daddr));
+
+ return sum;
+}
#endif /* IP_H */
diff --git a/tcp.c b/tcp.c
index 293ab12d8c21..2fd6bc2eda53 100644
--- a/tcp.c
+++ b/tcp.c
@@ -938,39 +938,25 @@ static void tcp_sock_set_bufsize(const struct ctx *c, int s)
* tcp_update_check_tcp4() - Update TCP checksum from stored one
* @buf: L2 packet buffer with final IPv4 header
*/
-static void tcp_update_check_tcp4(struct tcp4_l2_buf_t *buf)
+static uint16_t tcp_update_check_tcp4(struct iphdr *iph)
{
- uint16_t tlen = ntohs(buf->iph.tot_len) - 20;
- uint32_t sum = htons(IPPROTO_TCP);
+ struct tcphdr *th = (void *)(iph + 1);
+ uint16_t tlen = ntohs(iph->tot_len) - 20;
+ uint32_t sum = proto_ipv4_header_checksum(iph, IPPROTO_TCP);
- sum += (buf->iph.saddr >> 16) & 0xffff;
- sum += buf->iph.saddr & 0xffff;
- sum += (buf->iph.daddr >> 16) & 0xffff;
- sum += buf->iph.daddr & 0xffff;
- sum += htons(ntohs(buf->iph.tot_len) - 20);
-
- buf->th.check = 0;
- buf->th.check = csum(&buf->th, tlen, sum);
+ return csum(th, tlen, sum);
}
/**
* tcp_update_check_tcp6() - Calculate TCP checksum for IPv6
* @buf: L2 packet buffer with final IPv6 header
*/
-static void tcp_update_check_tcp6(struct tcp6_l2_buf_t *buf)
+static uint16_t tcp_update_check_tcp6(struct ipv6hdr *ip6h)
{
- int len = ntohs(buf->ip6h.payload_len) + sizeof(struct ipv6hdr);
-
- buf->ip6h.hop_limit = IPPROTO_TCP;
- buf->ip6h.version = 0;
- buf->ip6h.nexthdr = 0;
+ struct tcphdr *th = (void *)(ip6h + 1);
+ uint32_t sum = proto_ipv6_header_checksum(ip6h, IPPROTO_TCP);
- buf->th.check = 0;
- buf->th.check = csum(&buf->ip6h, len, 0);
-
- buf->ip6h.hop_limit = 255;
- buf->ip6h.version = 6;
- buf->ip6h.nexthdr = IPPROTO_TCP;
+ return csum(th, ntohs(ip6h->payload_len), sum);
}
/**
@@ -1381,7 +1367,7 @@ do { \
SET_TCP_HEADER_COMMON_V4_V6(b, conn, seq);
- tcp_update_check_tcp4(b);
+ b->th.check = tcp_update_check_tcp4(&b->iph);
tlen = tap_iov_len(c, &b->taph, ip_len);
} else {
@@ -1400,7 +1386,11 @@ do { \
SET_TCP_HEADER_COMMON_V4_V6(b, conn, seq);
- tcp_update_check_tcp6(b);
+ b->th.check = tcp_update_check_tcp6(&b->ip6h);
+
+ b->ip6h.hop_limit = 255;
+ b->ip6h.version = 6;
+ b->ip6h.nexthdr = IPPROTO_TCP;
b->ip6h.flow_lbl[0] = (conn->sock >> 16) & 0xf;
b->ip6h.flow_lbl[1] = (conn->sock >> 8) & 0xff;
diff --git a/udp.c b/udp.c
index 6f867df81c05..96b4e6ca9a85 100644
--- a/udp.c
+++ b/udp.c
@@ -669,10 +669,8 @@ static size_t udp_update_hdr6(const struct ctx *c, int n, in_port_t dstport,
b->uh.source = b->s_in6.sin6_port;
b->uh.dest = htons(dstport);
b->uh.len = b->ip6h.payload_len;
-
- b->ip6h.hop_limit = IPPROTO_UDP;
- b->ip6h.version = b->ip6h.nexthdr = b->uh.check = 0;
- b->uh.check = csum(&b->ip6h, ip_len, 0);
+ b->uh.check = csum(&b->uh, ntohs(b->ip6h.payload_len),
+ proto_ipv6_header_checksum(&b->ip6h, IPPROTO_UDP));
b->ip6h.version = 6;
b->ip6h.nexthdr = IPPROTO_UDP;
b->ip6h.hop_limit = 255;
--
2.42.0