Add csum_udp6() helper for calculating UDP over IPv6 checksums
Add a helper for calculating UDP checksums when used over IPv6 For future flexibility, the new helper takes parameters for the fields in the IPv6 pseudo-header, so an IPv6 header or pseudo-header doesn't need to be explicitly constructed. It also allows the UDP header and payload to be in separate buffers, although we don't use this yet. Signed-off-by: David Gibson <david@gibson.dropbear.id.au> Signed-off-by: Stefano Brivio <sbrivio@redhat.com>
This commit is contained in:
parent
67ab617172
commit
6905ac75ec
3 changed files with 28 additions and 3 deletions
22
checksum.c
22
checksum.c
|
@ -52,6 +52,7 @@
|
|||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <linux/udp.h>
|
||||
#include <linux/icmp.h>
|
||||
#include <linux/icmpv6.h>
|
||||
|
||||
|
@ -123,6 +124,27 @@ void csum_icmp4(struct icmphdr *icmp4hr, const void *payload, size_t len)
|
|||
icmp4hr->checksum = csum_unaligned(payload, len, psum);
|
||||
}
|
||||
|
||||
/**
|
||||
* csum_udp6() - Calculate and set checksum for a UDP over IPv6 packet
|
||||
* @udp6hr: UDP header, initialised apart from checksum
|
||||
* @payload: UDP packet payload
|
||||
* @len: Length of @payload (not including UDP header)
|
||||
*/
|
||||
void csum_udp6(struct udphdr *udp6hr,
|
||||
const struct in6_addr *saddr, const struct in6_addr *daddr,
|
||||
const void *payload, size_t len)
|
||||
{
|
||||
/* Partial checksum for the pseudo-IPv6 header */
|
||||
uint32_t psum = sum_16b(saddr, sizeof(*saddr)) +
|
||||
sum_16b(daddr, sizeof(*daddr)) +
|
||||
htons(len + sizeof(*udp6hr)) + htons(IPPROTO_UDP);
|
||||
|
||||
udp6hr->check = 0;
|
||||
/* Add in partial checksum for the UDP header alone */
|
||||
psum += sum_16b(udp6hr, sizeof(*udp6hr));
|
||||
udp6hr->check = csum_unaligned(payload, len, psum);
|
||||
}
|
||||
|
||||
/**
|
||||
* csum_icmp6() - Calculate and set checksum for an ICMPv6 packet
|
||||
* @icmp6hr: ICMPv6 header, initialised apart from checksum
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
#ifndef CHECKSUM_H
|
||||
#define CHECKSUM_H
|
||||
|
||||
struct udphdr;
|
||||
struct icmphdr;
|
||||
struct icmp6hdr;
|
||||
|
||||
|
@ -13,6 +14,9 @@ uint32_t sum_16b(const void *buf, size_t len);
|
|||
uint16_t csum_fold(uint32_t sum);
|
||||
uint16_t csum_unaligned(const void *buf, size_t len, uint32_t init);
|
||||
void csum_icmp4(struct icmphdr *ih, const void *payload, size_t len);
|
||||
void csum_udp6(struct udphdr *udp6hr,
|
||||
const struct in6_addr *saddr, const struct in6_addr *daddr,
|
||||
const void *payload, size_t len);
|
||||
void csum_icmp6(struct icmp6hdr *icmp6hr,
|
||||
const struct in6_addr *saddr, const struct in6_addr *daddr,
|
||||
const void *payload, size_t len);
|
||||
|
|
5
tap.c
5
tap.c
|
@ -183,9 +183,8 @@ void tap_ip_send(const struct ctx *c, const struct in6_addr *src, uint8_t proto,
|
|||
} else if (proto == IPPROTO_UDP) {
|
||||
struct udphdr *uh = (struct udphdr *)(ip6h + 1);
|
||||
|
||||
uh->check = 0;
|
||||
uh->check = csum_unaligned(ip6h, len + sizeof(*ip6h),
|
||||
0);
|
||||
csum_udp6(uh, &ip6h->saddr, &ip6h->daddr,
|
||||
uh + 1, len - sizeof(*uh));
|
||||
} else if (proto == IPPROTO_ICMPV6) {
|
||||
struct icmp6hdr *ih = (struct icmp6hdr *)(ip6h + 1);
|
||||
|
||||
|
|
Loading…
Reference in a new issue