I am calculating UDP checksum using the following function (found it somewhere):
uint16_t udp_checksum(const void *buff, size_t len, in_addr_t src_addr, in_addr_t dest_addr)
{
const uint16_t *buf=(const uint16_t *)buff;
uint16_t *ip_src=(uint16_t *)&src_addr,
*ip_dst=(uint16_t *)&dest_addr;
uint32_t sum;
size_t length=len;
// Calculate the sum
sum = 0;
while (len > 1)
{
sum += *buf++;
if (sum & 0x80000000)
sum = (sum & 0xFFFF) + (sum >> 16);
len -= 2;
}
if ( len & 1 )
// Add the padding if the packet length is odd
sum += *((uint8_t *)buf);
// Add the pseudo-header
sum += *(ip_src++);
sum += *ip_src;
sum += *(ip_dst++);
sum += *ip_dst;
sum += htons(IPROTO_UDP);
sum += htons(length);
// Add the carries
while (sum >> 16)
sum = (sum & 0xFFFF) + (sum >> 16);
// Return the one's complement of sum
return ( (uint16_t)(~sum) );
}
int form_checksums(char * buff)
{
// Get IP and UDP headers
IP_Header* ipHdr = (IP_Header*)(buff);
struct UDP_Header* udpHdr = (struct UDP_Header*) (buff + 4*ipHdr->ihl);
//---- Form and fill IP checksum now--------------------------------------
ipHdr->check = 0;
ipHdr->check = in_cksum((unsigned short *)ipHdr, sizeof(*ipHdr));
//---- calculate and fill udp checksum now ---
udpHdr->checksum = 0;
udpHdr->checksum = udp_checksum(buff + 4*ipHdr->ihl, udpHdr->length, ipHdr->saddr, ipHdr->daddr);
return 0;
}
Wireshark shows that the wrong UDP checksum is calculated. I don't see any problem in the function. What can be going wrong?