The following code should calculate the TCP Checksum, but for unknown reasons, it doesn't calculate it correctly.
#define MAX_CSUM_WORDS 750
static __always_inline __u32 sum16(const void* data, __u32 size, const void* data_end) {
__u32 s = 0;
#pragma unroll
for (__u32 i = 0; i < MAX_CSUM_WORDS; i++) {
if (2*i >= size) {
return s; /* normal exit */
}
if (data + 2*i + 1 + 1 > data_end) {
return 0; /* should be unreachable */
}
s += ((const __u16*)data)[i];
if (2*i + 1 == size) {
if (data + (i*2+2) > data_end) {
return 0;
}else{
s += ((const __u8*)data)[i*2+1];
return s;
}
}
}
return s;
}
static __always_inline __u32 sum16_32(__u32 v) {
return (v >> 16) + (v & 0xffff);
}
static __always_inline __u16 carry(__u32 csum) {
csum = (csum & 0xffff) + (csum >> 16);
csum = (csum & 0xffff) + (csum >> 16); // loop
return ~csum;
}
// Inside the main code
unsigned int payload_len = ntohs(iph->tot_len) - (iph->ihl * 4 + tcph->doff * 4);
__u32 tcp_csum = 0;
tcp_csum += sum16_32(iph->saddr);
tcp_csum += sum16_32(iph->daddr);
tcp_csum += 0x0600;
tcp_csum += (uint16_t)(((tcph->doff * 4) + payload_len));
tcph->check = 0;
tcp_csum += sum16(tcph, ((tcph->doff * 4) + payload_len), data_end);
tcph->check = carry(tcp_csum);
The payload length of the packet I'm testing on is 125 byte.
carry and sum16_32 and sum16 are copied from an XDP SYN Cookie project. I just have edited sum16 to handle odd-byte cases.
Thank you for helping in advance.