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:
  1. static void convert_hex_to_uint8(const char *data_hex)
  2. {
  3.     unsigned int temp;
  4.     for (size_t i = 0; i < sizeof(mensajeUDP); i++) {
  5.         sscanf(&data_hex[i*3], "%02x", &temp);
  6.         mensajeUDP[i] = temp;
  7.     }
  8. }
  9.  
  10. static void enviarConfiguracionABalanza(void)
  11. {
  12. uint8_t src_mac[] = {0x00, 0x08, 0xef, 0x00, 0x01, 0x37};
  13. uint8_t dest_mac[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
  14. uint32_t src_ip = 0xc0a80a98;
  15. uint32_t dest_ip = 0xc0a80aff;
  16. uint16_t src_port = 6000;
  17. uint16_t dest_port = 6000;
  18. int msg_len;
  19.    
  20.     if (enviarRespuestaUDP == false)
  21.         return;
  22.     else
  23.         enviarRespuestaUDP = false;
  24.  
  25.     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";
  26.     msg_len = strlen(data_hex);
  27.     printf ("%d",msg_len);
  28.     convert_hex_to_uint8(data_hex);
  29.  
  30.     ethernet_header_t *eth_header = (ethernet_header_t *)bufferUDP;
  31.     ip_header_t *ip_header = (ip_header_t *)(bufferUDP + sizeof(ethernet_header_t));
  32.     udp_header_t *udp_header = (udp_header_t *)(bufferUDP + sizeof(ethernet_header_t) + sizeof(ip_header_t));
  33.  
  34.     memcpy(eth_header->src_mac, src_mac, 6);
  35.     memcpy(eth_header->dest_mac, dest_mac, 6);
  36.     eth_header->ethertype = htons(0x0800); // IP
  37.  
  38.     ip_header->version_ihl = 0x45;
  39.     ip_header->type_of_service = 0;
  40.     ip_header->total_length = 0x2001;
  41.     ip_header->identification = 0x2900;
  42.     ip_header->flags_fragment_offset = 0;
  43.     ip_header->ttl = 128;
  44.     ip_header->header_checksum = 0;
  45.     ip_header->protocol = 17; // UDP
  46.     ip_header->src_ip = htonl(src_ip);
  47.     ip_header->dest_ip = htonl(dest_ip);
  48.  
  49.     ip_header->header_checksum = calculate_ip_checksum(ip_header);
  50.  
  51.     udp_header->src_port = htons(src_port);
  52.     udp_header->dest_port = htons(dest_port);
  53.     udp_header->checksum = 0;
  54.     udp_header->length = 0x0c01;
  55.  
  56.     udp_header->checksum = calculate_udp_checksum(ip_header, udp_header, mensajeUDP, 260);
  57.  
  58.     memcpy(bufferUDP + sizeof(ethernet_header_t) + sizeof(ip_header_t) + sizeof(udp_header_t), mensajeUDP, 260);
  59.  
  60.     if (esp_eth_transmit(s_eth_handle[0], bufferUDP, 302) != ESP_OK)
  61.         ESP_LOGE(TAG, "Error");
  62. }
  63.  
  64. static uint16_t calculate_checksum(uint16_t *buffer, int length)
  65. {
  66.     uint32_t sum = 0;
  67.  
  68.     while (length > 1) {
  69.         sum += *buffer++;
  70.         length -= 2;
  71.     }
  72.  
  73.     if (length > 0) {
  74.         sum += *(uint8_t *)buffer;
  75.     }
  76.  
  77.     while (sum >> 16) {
  78.         sum = (sum & 0xffff) + (sum >> 16);
  79.     }
  80.  
  81.     return (uint16_t)~sum;
  82. }
  83.  
  84. static uint16_t calculate_ip_checksum(ip_header_t *ip_header)
  85. {
  86.     ip_header->header_checksum = 0;
  87.     return (calculate_checksum((uint16_t *)ip_header, sizeof(ip_header_t)));
  88. }
  89.  
  90. static uint16_t calculate_udp_checksum(ip_header_t *ip_header, udp_header_t *udp_header, uint8_t *data, uint16_t data_len)
  91. {
  92.     uint16_t total_length = sizeof(udp_header_t) + data_len;
  93.  
  94.     uint8_t pseudo_header_buffer[sizeof(pseudo_header_t) + sizeof(udp_header_t)];
  95.     pseudo_header_t *pseudo_header = (pseudo_header_t *)pseudo_header_buffer;
  96.  
  97.     pseudo_header->src_ip = ip_header->src_ip;
  98.     pseudo_header->dest_ip = ip_header->dest_ip;
  99.     pseudo_header->zero = 0;
  100.     pseudo_header->protocol = ip_header->protocol;
  101.     pseudo_header->udp_length = htons(total_length);
  102.  
  103.     uint32_t sum = 0;
  104.  
  105.     sum += calculate_checksum((uint16_t *)pseudo_header, sizeof(pseudo_header_t));
  106.     sum += calculate_checksum((uint16_t *)udp_header, sizeof(udp_header_t));
  107.     sum += calculate_checksum((uint16_t *)data, data_len);
  108.  
  109.     while (sum >> 16) {
  110.         sum = (sum & 0xffff) + (sum >> 16);
  111.     }
  112.     return (uint16_t)~sum;
  113. }
  114.  
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: 1734
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

endi83 wrote:
Mon Mar 25, 2024 1:05 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: 2378
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: No registered users and 72 guests