]> git.ipfire.org Git - thirdparty/bird.git/blame - lib/checksum.c
Added library progdocs.
[thirdparty/bird.git] / lib / checksum.c
CommitLineData
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
5e13ffe6
MM
18static u16 /* One-complement addition */
19add16(u16 sum, u16 x)
20{
21 u16 z = sum + x;
22 return z + (z < sum);
23}
24
25static u32
26add32(u32 sum, u32 x)
27{
28 u32 z = sum + x;
29 return z + (z < sum);
30}
31
32static u16
33ipsum_calc_block(u16 *x, unsigned len, u16 sum)
34{
35 int rest;
36 u32 tmp, *xx;
37
38 /*
39 * A few simple facts about the IP checksum (see RFC 1071 for detailed
40 * discussion):
41 *
42 * o It's associative and commutative.
43 * o It's byte order independent.
44 * o It's word size independent.
45 *
46 * This gives us a neat 32-bits-at-a-time algorithm which respects
47 * usual alignment requirements and is reasonably fast.
48 */
49
50 ASSERT(!(len % 2));
51 if (!len)
52 return sum;
53 len >>= 1;
54 if ((unsigned long) x & 2) /* Align to 32-bit boundary */
55 {
56 sum = add16(sum, *x++);
57 len--;
58 }
59 rest = len & 1;
60 len >>= 1;
61 tmp = 0;
62 xx = (u32 *) x;
63 while (len)
64 {
65 tmp = add32(tmp, *xx++);
66 len--;
67 }
68 sum = add16(sum, add16(tmp & 0xffff, tmp >> 16U));
69 if (rest)
70 sum = add16(sum, *(u16 *) xx);
71 return sum;
72}
73
1a54d44a
MM
74static u16
75ipsum_calc(void *frag, unsigned len, va_list args)
76{
77 u16 sum = 0;
78
79 for(;;)
80 {
5e13ffe6 81 sum = ipsum_calc_block(frag, len, sum);
1a54d44a
MM
82 frag = va_arg(args, void *);
83 if (!frag)
84 break;
85 len = va_arg(args, unsigned);
86 }
87 return sum;
88}
89
7722938d
MM
90/**
91 * ipsum_verify - verify an IP checksum
92 * @frag: first packet fragment
93 * @len: length in bytes
94 *
95 * This function verifies whether a given fragmented packet
96 * has correct one's complement checksum as used by the IP
97 * protocol.
98 *
99 * It uses all the clever tricks described in RFC 1071 to speed
100 * up checksum calculation as much as possible.
101 *
102 * Result: 1 if the checksum is correct, 0 else.
103 */
1a54d44a
MM
104int
105ipsum_verify(void *frag, unsigned len, ...)
106{
107 va_list args;
108 u16 sum;
109
110 va_start(args, len);
111 sum = ipsum_calc(frag, len, args);
112 va_end(args);
113 return sum == 0xffff;
114}
115
7722938d
MM
116/**
117 * ipsum_calculate - compute an IP checksum
118 * @frag: first packet fragment
119 * @len: length in bytes
120 *
121 * This function caculates a one's complement checksum of a given fragmented
122 * packet.
123 *
124 * It uses all the clever tricks described in RFC 1071 to speed
125 * up checksum calculation as much as possible.
126 */
1a54d44a
MM
127u16
128ipsum_calculate(void *frag, unsigned len, ...)
129{
130 va_list args;
131 u16 sum;
132
133 va_start(args, len);
134 sum = ipsum_calc(frag, len, args);
135 va_end(args);
136 return 0xffff - sum;
137}