blob: 240da431e34827a937b8d7fa2b8db392315e0426 [file] [log] [blame]
Stefan Reinauer6540ae52007-07-12 16:35:42 +00001/*****************************************************************************\
2 * compute_ip_checksum.c
Stefan Reinauer6540ae52007-07-12 16:35:42 +00003\*****************************************************************************/
4
5#include <stdint.h>
6#include "ip_checksum.h"
7
Stefan Reinauerf527e702008-01-18 15:33:49 +00008/* Note: The contents of this file were borrowed from the coreboot source
Paul Menzela8843de2017-06-05 12:33:23 +02009 * code which may be obtained from https://www.coreboot.org.
Stefan Reinauerf527e702008-01-18 15:33:49 +000010 * Specifically, this code was obtained from coreboot (LinuxBIOS)
11 * version 1.0.0.8.
Stefan Reinauer6540ae52007-07-12 16:35:42 +000012 */
13
14unsigned long compute_ip_checksum(void *addr, unsigned long length)
15{
Stefan Reinauer90b96b62010-01-13 21:00:23 +000016 uint8_t *ptr;
17 volatile union {
18 uint8_t byte[2];
19 uint16_t word;
20 } value;
21 unsigned long sum;
22 unsigned long i;
23 /* In the most straight forward way possible,
24 * compute an ip style checksum.
25 */
26 sum = 0;
27 ptr = addr;
28 for (i = 0; i < length; i++) {
29 unsigned long value;
30 value = ptr[i];
31 if (i & 1) {
32 value <<= 8;
33 }
34 /* Add the new value */
35 sum += value;
36 /* Wrap around the carry */
37 if (sum > 0xFFFF) {
38 sum = (sum + (sum >> 16)) & 0xFFFF;
39 }
40 }
41 value.byte[0] = sum & 0xff;
42 value.byte[1] = (sum >> 8) & 0xff;
43 return (~value.word) & 0xFFFF;
Stefan Reinauer6540ae52007-07-12 16:35:42 +000044}