]>
Commit | Line | Data |
---|---|---|
1a54d44a MM |
1 | /* |
2 | * BIRD Library -- IP One-Complement Checksum | |
3 | * | |
7722938d | 4 | * (c) 1999--2000 Martin Mares <mj@ucw.cz> |
1a54d44a MM |
5 | * |
6 | * Can be freely distributed and used under the terms of the GNU GPL. | |
7 | */ | |
8 | ||
7722938d MM |
9 | /** |
10 | * DOC: Miscellaneous functions. | |
11 | */ | |
12 | ||
1a54d44a MM |
13 | #include <stdarg.h> |
14 | ||
15 | #include "nest/bird.h" | |
16 | #include "checksum.h" | |
17 | ||
c1b51598 | 18 | static inline u32 |
5e13ffe6 MM |
19 | add32(u32 sum, u32 x) |
20 | { | |
21 | u32 z = sum + x; | |
c1b51598 OZ |
22 | // return z + (z < sum); |
23 | ||
24 | /* add carry */ | |
25 | if (z < x) | |
26 | z++; | |
27 | return z; | |
5e13ffe6 MM |
28 | } |
29 | ||
30 | static u16 | |
ae80a2de | 31 | ipsum_calc_block(u32 *buf, uint len, u16 isum) |
5e13ffe6 | 32 | { |
5e13ffe6 MM |
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 | ||
c1b51598 | 45 | ASSERT(!(len % 4)); |
5e13ffe6 | 46 | if (!len) |
c1b51598 OZ |
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 */ | |
5e13ffe6 MM |
56 | return sum; |
57 | } | |
58 | ||
1a54d44a | 59 | static u16 |
ae80a2de | 60 | ipsum_calc(void *frag, uint len, va_list args) |
1a54d44a MM |
61 | { |
62 | u16 sum = 0; | |
63 | ||
64 | for(;;) | |
65 | { | |
5e13ffe6 | 66 | sum = ipsum_calc_block(frag, len, sum); |
1a54d44a MM |
67 | frag = va_arg(args, void *); |
68 | if (!frag) | |
69 | break; | |
ae80a2de | 70 | len = va_arg(args, uint); |
1a54d44a MM |
71 | } |
72 | return sum; | |
73 | } | |
74 | ||
7722938d MM |
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 | */ | |
1a54d44a | 89 | int |
ae80a2de | 90 | ipsum_verify(void *frag, uint len, ...) |
1a54d44a MM |
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 | ||
7722938d MM |
101 | /** |
102 | * ipsum_calculate - compute an IP checksum | |
103 | * @frag: first packet fragment | |
104 | * @len: length in bytes | |
105 | * | |
2e9b2421 | 106 | * This function calculates a one's complement checksum of a given fragmented |
7722938d MM |
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 | */ | |
1a54d44a | 112 | u16 |
ae80a2de | 113 | ipsum_calculate(void *frag, uint len, ...) |
1a54d44a MM |
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 | } |