csum_ip4_header() takes the packet length as a network endian value. In
general it's very error-prone to pass non-native-endian values as a raw
integer. It's particularly bad here because this differs from other
checksum functions (e.g. proto_ipv4_header_psum()) which take host native
lengths.
It turns out all the callers have easy access to the native endian value,
so switch it to use host order like everything else.
Signed-off-by: David Gibson
---
checksum.c | 4 ++--
tap.c | 6 ++++--
tcp.c | 2 +-
udp.c | 2 +-
4 files changed, 8 insertions(+), 6 deletions(-)
diff --git a/checksum.c b/checksum.c
index a5a506c7..b330e1ef 100644
--- a/checksum.c
+++ b/checksum.c
@@ -116,7 +116,7 @@ uint16_t csum_fold(uint32_t sum)
/**
* csum_ip4_header() - Calculate IPv4 header checksum
- * @tot_len: IPv4 payload length (data + IP header, network order)
+ * @tot_len: IPv4 packet length (data + IP header, host order)
* @protocol: Protocol number
* @saddr: IPv4 source address
* @daddr: IPv4 destination address
@@ -128,7 +128,7 @@ uint16_t csum_ip4_header(uint16_t tot_len, uint8_t protocol,
{
uint32_t sum = L2_BUF_IP4_PSUM(protocol);
- sum += tot_len;
+ sum += htons(tot_len);
sum += (saddr.s_addr >> 16) & 0xffff;
sum += saddr.s_addr & 0xffff;
sum += (daddr.s_addr >> 16) & 0xffff;
diff --git a/tap.c b/tap.c
index d0ef6b5c..230566ba 100644
--- a/tap.c
+++ b/tap.c
@@ -149,17 +149,19 @@ static void *tap_push_l2h(const struct ctx *c, void *buf, uint16_t proto)
static void *tap_push_ip4h(struct iphdr *ip4h, struct in_addr src,
struct in_addr dst, size_t len, uint8_t proto)
{
+ uint16_t tot_len = len + sizeof(*ip4h);
+
ip4h->version = 4;
ip4h->ihl = sizeof(struct iphdr) / 4;
ip4h->tos = 0;
- ip4h->tot_len = htons(len + sizeof(*ip4h));
+ ip4h->tot_len = htons(tot_len);
ip4h->id = 0;
ip4h->frag_off = 0;
ip4h->ttl = 255;
ip4h->protocol = proto;
ip4h->saddr = src.s_addr;
ip4h->daddr = dst.s_addr;
- ip4h->check = csum_ip4_header(ip4h->tot_len, proto, src, dst);
+ ip4h->check = csum_ip4_header(tot_len, proto, src, dst);
return ip4h + 1;
}
diff --git a/tcp.c b/tcp.c
index 24f99cdf..3ba3aa4d 100644
--- a/tcp.c
+++ b/tcp.c
@@ -1359,7 +1359,7 @@ static size_t tcp_fill_headers4(const struct ctx *c,
iph->daddr = c->ip4.addr_seen.s_addr;
iph->check = check ? *check :
- csum_ip4_header(iph->tot_len, IPPROTO_TCP,
+ csum_ip4_header(ip_len, IPPROTO_TCP,
*a4, c->ip4.addr_seen);
tcp_fill_header(th, conn, seq);
diff --git a/udp.c b/udp.c
index 4bf90591..09f98130 100644
--- a/udp.c
+++ b/udp.c
@@ -605,7 +605,7 @@ static size_t udp_update_hdr4(const struct ctx *c, struct udp4_l2_buf_t *b,
b->iph.tot_len = htons(ip_len);
b->iph.daddr = c->ip4.addr_seen.s_addr;
b->iph.saddr = src.s_addr;
- b->iph.check = csum_ip4_header(b->iph.tot_len, IPPROTO_UDP,
+ b->iph.check = csum_ip4_header(ip_len, IPPROTO_UDP,
src, c->ip4.addr_seen);
b->uh.source = b->s_in.sin_port;
--
2.44.0