blob: f19e94387a7f1ce421a191962f8a7a210a2bfd65 [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
9 * code which may be obtained from http://www.coreboot.org.
10 * 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}