Calculating the checksum of a UDP packet

endi83
Posts: 24
Joined: Wed Nov 22, 2023 2:43 pm

Calculating the checksum of a UDP packet

Postby endi83 » Mon Mar 25, 2024 1:05 pm

In an ESP32C6 project I am sending UDP packets over ethernet to another device. I am trying to calculate the checksum of the UDP packet I have to send.
To do this I have:

Code: Untitled.c Select all


static void convert_hex_to_uint8(const char *data_hex)
{
unsigned int temp;
for (size_t i = 0; i < sizeof(mensajeUDP); i++) {
sscanf(&data_hex[i*3], "%02x", &temp);
mensajeUDP[i] = temp;
}
}

static void enviarConfiguracionABalanza(void)
{
uint8_t src_mac[] = {0x00, 0x08, 0xef, 0x00, 0x01, 0x37};
uint8_t dest_mac[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
uint32_t src_ip = 0xc0a80a98;
uint32_t dest_ip = 0xc0a80aff;
uint16_t src_port = 6000;
uint16_t dest_port = 6000;
int msg_len;

if (enviarRespuestaUDP == false)
return;
else
enviarRespuestaUDP = false;

const char *data_hex = "44 50 48 00 04 01 00 ff 00 00 00 00 02 00 00 00 01 00 00 00 00 00 00 00 00 00 00 00 01 4d 41 53 00 2a 2a 2a 2a 2a 2a 2a 2a 2a 2a 2a 2b 2b 2b 2b 2b 2b 2b 2b 2b 00 2a 2a 2a 2a 2a 2a 2a 2a 2a 2a 98 0a a8 c0 0e 00 00 00 31 31 37 00 20 20 45 00 00 00 00 00 01 00 00 00 46 00 00 00 30 2e 31 37 00 00 00 00 00 00 00 05 30 00 00 03 00 00 00 00 00 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ff ff ff 00 00 01 00 00 00 00 00";
msg_len = strlen(data_hex);
printf ("%d",msg_len);
convert_hex_to_uint8(data_hex);

ethernet_header_t *eth_header = (ethernet_header_t *)bufferUDP;
ip_header_t *ip_header = (ip_header_t *)(bufferUDP + sizeof(ethernet_header_t));
udp_header_t *udp_header = (udp_header_t *)(bufferUDP + sizeof(ethernet_header_t) + sizeof(ip_header_t));

memcpy(eth_header->src_mac, src_mac, 6);
memcpy(eth_header->dest_mac, dest_mac, 6);
eth_header->ethertype = htons(0x0800); // IP

ip_header->version_ihl = 0x45;
ip_header->type_of_service = 0;
ip_header->total_length = 0x2001;
ip_header->identification = 0x2900;
ip_header->flags_fragment_offset = 0;
ip_header->ttl = 128;
ip_header->header_checksum = 0;
ip_header->protocol = 17; // UDP
ip_header->src_ip = htonl(src_ip);
ip_header->dest_ip = htonl(dest_ip);

ip_header->header_checksum = calculate_ip_checksum(ip_header);

udp_header->src_port = htons(src_port);
udp_header->dest_port = htons(dest_port);
udp_header->checksum = 0;
udp_header->length = 0x0c01;

udp_header->checksum = calculate_udp_checksum(ip_header, udp_header, mensajeUDP, 260);

memcpy(bufferUDP + sizeof(ethernet_header_t) + sizeof(ip_header_t) + sizeof(udp_header_t), mensajeUDP, 260);

if (esp_eth_transmit(s_eth_handle[0], bufferUDP, 302) != ESP_OK)
ESP_LOGE(TAG, "Error");
}

static uint16_t calculate_checksum(uint16_t *buffer, int length)
{
uint32_t sum = 0;

while (length > 1) {
sum += *buffer++;
length -= 2;
}

if (length > 0) {
sum += *(uint8_t *)buffer;
}

while (sum >> 16) {
sum = (sum & 0xffff) + (sum >> 16);
}

return (uint16_t)~sum;
}

static uint16_t calculate_ip_checksum(ip_header_t *ip_header)
{
ip_header->header_checksum = 0;
return (calculate_checksum((uint16_t *)ip_header, sizeof(ip_header_t)));
}

static uint16_t calculate_udp_checksum(ip_header_t *ip_header, udp_header_t *udp_header, uint8_t *data, uint16_t data_len)
{
uint16_t total_length = sizeof(udp_header_t) + data_len;

uint8_t pseudo_header_buffer[sizeof(pseudo_header_t) + sizeof(udp_header_t)];
pseudo_header_t *pseudo_header = (pseudo_header_t *)pseudo_header_buffer;

pseudo_header->src_ip = ip_header->src_ip;
pseudo_header->dest_ip = ip_header->dest_ip;
pseudo_header->zero = 0;
pseudo_header->protocol = ip_header->protocol;
pseudo_header->udp_length = htons(total_length);

uint32_t sum = 0;

sum += calculate_checksum((uint16_t *)pseudo_header, sizeof(pseudo_header_t));
sum += calculate_checksum((uint16_t *)udp_header, sizeof(udp_header_t));
sum += calculate_checksum((uint16_t *)data, data_len);

while (sum >> 16) {
sum = (sum & 0xffff) + (sum >> 16);
}
return (uint16_t)~sum;
}
I know that the result of the checksum of the UDP header is "ec 16" but the result I get is "13 e9".

Can someone tell me what I have wrong?

MicroController
Posts: 2672
Joined: Mon Oct 17, 2022 7:38 pm
Location: Europe, Germany

Re: Calculating the checksum of a UDP packet

Postby MicroController » Mon Mar 25, 2024 1:40 pm

I know that the result of the checksum of the UDP header is "ec 16" but the result I get is "13 e9".

Can someone tell me what I have wrong?
0xec16 happens to be (0x13e9 ^ 0xffff), which hints at one inversion too much.
See e.g. https://gist.github.com/fxlv/81209bbd15 ... 5ff076c9f3
You'd need to sum up all values first, then invert only once at the end. So you may want to change "return (uint16_t)~sum;" in calculate_checksum(...) to "return (uint16_t)sum;" but keep the single inversion at the end of calculate_udp_checksum(...).

endi83
Posts: 24
Joined: Wed Nov 22, 2023 2:43 pm

Re: Calculating the checksum of a UDP packet

Postby endi83 » Mon Mar 25, 2024 3:02 pm

Thanks to your comment I managed to solve the problem!

chegewara
Posts: 2505
Joined: Wed Jun 14, 2017 9:00 pm

Re: Calculating the checksum of a UDP packet

Postby chegewara » Mon Mar 25, 2024 6:31 pm

Maybe late and stupid question, but since when you are passing uint16_t* to calculate CRC?

Code: Select all

uint16_t calculate_checksum(uint16_t *buffer, int length)

Who is online

Users browsing this forum: ChatGPT-User, Qwantbot and 7 guests