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