]> git.ipfire.org Git - thirdparty/bird.git/blob - lib/checksum.c
OSPF: Support for graceful restart
[thirdparty/bird.git] / lib / checksum.c
1 /*
2 * BIRD Library -- IP One-Complement Checksum
3 *
4 * (c) 1999--2000 Martin Mares <mj@ucw.cz>
5 *
6 * Can be freely distributed and used under the terms of the GNU GPL.
7 */
8
9 /**
10 * DOC: Miscellaneous functions.
11 */
12
13 #include <stdarg.h>
14
15 #include "nest/bird.h"
16 #include "checksum.h"
17
18 static inline u32
19 add32(u32 sum, u32 x)
20 {
21 u32 z = sum + x;
22 // return z + (z < sum);
23
24 /* add carry */
25 if (z < x)
26 z++;
27 return z;
28 }
29
30 static u16
31 ipsum_calc_block(u32 *buf, uint len, u16 isum)
32 {
33 /*
34 * A few simple facts about the IP checksum (see RFC 1071 for detailed
35 * discussion):
36 *
37 * o It's associative and commutative.
38 * o It's byte order independent.
39 * o It's word size independent.
40 *
41 * This gives us a neat 32-bits-at-a-time algorithm which respects
42 * usual alignment requirements and is reasonably fast.
43 */
44
45 ASSERT(!(len % 4));
46 if (!len)
47 return isum;
48
49 u32 *end = buf + (len >> 2);
50 u32 sum = isum;
51 while (buf < end)
52 sum = add32(sum, *buf++);
53
54 sum = (sum >> 16) + (sum & 0xffff); /* add high-16 to low-16 */
55 sum += (sum >> 16); /* add carry */
56 return sum;
57 }
58
59 static u16
60 ipsum_calc(void *frag, uint len, va_list args)
61 {
62 u16 sum = 0;
63
64 for(;;)
65 {
66 sum = ipsum_calc_block(frag, len, sum);
67 frag = va_arg(args, void *);
68 if (!frag)
69 break;
70 len = va_arg(args, uint);
71 }
72 return sum;
73 }
74
75 /**
76 * ipsum_verify - verify an IP checksum
77 * @frag: first packet fragment
78 * @len: length in bytes
79 *
80 * This function verifies whether a given fragmented packet
81 * has correct one's complement checksum as used by the IP
82 * protocol.
83 *
84 * It uses all the clever tricks described in RFC 1071 to speed
85 * up checksum calculation as much as possible.
86 *
87 * Result: 1 if the checksum is correct, 0 else.
88 */
89 int
90 ipsum_verify(void *frag, uint len, ...)
91 {
92 va_list args;
93 u16 sum;
94
95 va_start(args, len);
96 sum = ipsum_calc(frag, len, args);
97 va_end(args);
98 return sum == 0xffff;
99 }
100
101 /**
102 * ipsum_calculate - compute an IP checksum
103 * @frag: first packet fragment
104 * @len: length in bytes
105 *
106 * This function calculates a one's complement checksum of a given fragmented
107 * packet.
108 *
109 * It uses all the clever tricks described in RFC 1071 to speed
110 * up checksum calculation as much as possible.
111 */
112 u16
113 ipsum_calculate(void *frag, uint len, ...)
114 {
115 va_list args;
116 u16 sum;
117
118 va_start(args, len);
119 sum = ipsum_calc(frag, len, args);
120 va_end(args);
121 return 0xffff - sum;
122 }