Annotation of embedaddon/bird/lib/fletcher16.h, revision 1.1.1.1
1.1 misho 1: /*
2: * BIRD Library -- Fletcher-16 checksum
3: *
4: * (c) 2015 Ondrej Zajicek <santiago@crfreenet.org>
5: * (c) 2015 CZ.NIC z.s.p.o.
6: *
7: * Can be freely distributed and used under the terms of the GNU GPL.
8: */
9:
10: /**
11: * DOC: Fletcher-16 checksum
12: *
13: * Fletcher-16 checksum is a position-dependent checksum algorithm used for
14: * error-detection e.g. in OSPF LSAs.
15: *
16: * To generate Fletcher-16 checksum, zero the checksum field in data, initialize
17: * the context by fletcher16_init(), process the data by fletcher16_update(),
18: * compute the checksum value by fletcher16_final() and store it to the checksum
19: * field in data by put_u16() (or other means involving htons() conversion).
20: *
21: * To verify Fletcher-16 checksum, initialize the context by fletcher16_init(),
22: * process the data by fletcher16_update(), compute a passing checksum by
23: * fletcher16_compute() and check if it is zero.
24: */
25:
26: #ifndef _BIRD_FLETCHER16_H_
27: #define _BIRD_FLETCHER16_H_
28:
29: #include "nest/bird.h"
30:
31:
32: struct fletcher16_context
33: {
34: int c0, c1;
35: };
36:
37:
38: /**
39: * fletcher16_init - initialize Fletcher-16 context
40: * @ctx: the context
41: */
42: static inline void
43: fletcher16_init(struct fletcher16_context *ctx)
44: {
45: ctx->c0 = ctx->c1 = 0;
46: }
47:
48: /**
49: * fletcher16_update - process data to Fletcher-16 context
50: * @ctx: the context
51: * @buf: data buffer
52: * @len: data length
53: *
54: * fletcher16_update() reads data from the buffer @buf and updates passing sums
55: * in the context @ctx. It may be used multiple times for multiple blocks of
56: * checksummed data.
57: */
58: static inline void
59: fletcher16_update(struct fletcher16_context *ctx, const u8* buf, int len)
60: {
61: /*
62: * The Fletcher-16 sum is essentially a sequence of
63: * ctx->c1 += ctx->c0 += *buf++, modulo 255.
64: *
65: * In the inner loop, we eliminate modulo operation and we do some loop
66: * unrolling. MODX is the maximal number of steps that can be done without
67: * modulo before overflow, see RFC 1008 for details. We use a bit smaller
68: * value to cover for initial steps due to loop unrolling.
69: */
70:
71: #define MODX 4096
72:
73: int blen, i;
74:
75: blen = len % 4;
76: len -= blen;
77:
78: for (i = 0; i < blen; i++)
79: ctx->c1 += ctx->c0 += *buf++;
80:
81: do {
82: blen = MIN(len, MODX);
83: len -= blen;
84:
85: for (i = 0; i < blen; i += 4)
86: {
87: ctx->c1 += ctx->c0 += *buf++;
88: ctx->c1 += ctx->c0 += *buf++;
89: ctx->c1 += ctx->c0 += *buf++;
90: ctx->c1 += ctx->c0 += *buf++;
91: }
92:
93: ctx->c0 %= 255;
94: ctx->c1 %= 255;
95:
96: } while (len);
97: }
98:
99:
100: /**
101: * fletcher16_update_n32 - process data to Fletcher-16 context, with endianity adjustment
102: * @ctx: the context
103: * @buf: data buffer
104: * @len: data length
105: *
106: * fletcher16_update_n32() works like fletcher16_update(), except it applies
107: * 32-bit host/network endianity swap to the data before they are processed.
108: * I.e., it assumes that the data is a sequence of u32 that must be converted by
109: * ntohl() or htonl() before processing. The @buf need not to be aligned, but
110: * its length (@len) must be multiple of 4. Note that on big endian systems the
111: * host endianity is the same as the network endianity, therefore there is no
112: * endianity swap.
113: */
114: static inline void
115: fletcher16_update_n32(struct fletcher16_context *ctx, const u8* buf, int len)
116: {
117: /* See fletcher16_update() for details */
118:
119: int blen, i;
120:
121: do {
122: blen = MIN(len, MODX);
123: len -= blen;
124:
125: for (i = 0; i < blen; i += 4)
126: {
127: #ifdef CPU_BIG_ENDIAN
128: ctx->c1 += ctx->c0 += *buf++;
129: ctx->c1 += ctx->c0 += *buf++;
130: ctx->c1 += ctx->c0 += *buf++;
131: ctx->c1 += ctx->c0 += *buf++;
132: #else
133: ctx->c1 += ctx->c0 += buf[3];
134: ctx->c1 += ctx->c0 += buf[2];
135: ctx->c1 += ctx->c0 += buf[1];
136: ctx->c1 += ctx->c0 += buf[0];
137: buf += 4;
138: #endif
139: }
140:
141: ctx->c0 %= 255;
142: ctx->c1 %= 255;
143:
144: } while (len);
145: }
146:
147: /**
148: * fletcher16_final - compute final Fletcher-16 checksum value
149: * @ctx: the context
150: * @len: total data length
151: * @pos: offset in data where the checksum will be stored
152: *
153: * fletcher16_final() computes the final checksum value and returns it.
154: * The caller is responsible for storing it in the appropriate position.
155: * The checksum value depends on @len and @pos, but only their difference
156: * (i.e. the offset from the end) is significant.
157: *
158: * The checksum value is represented as u16, although it is defined as two
159: * consecutive bytes. We treat them as one u16 in big endian / network order.
160: * I.e., the returned value is in the form that would be returned by get_u16()
161: * from the checksum field in the data buffer, therefore the caller should use
162: * put_u16() or an explicit host-to-network conversion when storing it to the
163: * checksum field in the data buffer.
164: *
165: * Note that the returned checksum value is always nonzero.
166: */
167: static inline u16
168: fletcher16_final(struct fletcher16_context *ctx, int len, int pos)
169: {
170: int x = ((len - pos - 1) * ctx->c0 - ctx->c1) % 255;
171: if (x <= 0)
172: x += 255;
173:
174: int y = 510 - ctx->c0 - x;
175: if (y > 255)
176: y -= 255;
177:
178: return (x << 8) | y;
179: }
180:
181:
182: /**
183: * fletcher16_compute - compute Fletcher-16 sum for verification
184: * @ctx: the context
185: *
186: * fletcher16_compute() returns a passing Fletcher-16 sum for processed data.
187: * If the data contains the proper Fletcher-16 checksum value, the returned
188: * value is zero.
189: */
190: static inline u16
191: fletcher16_compute(struct fletcher16_context *ctx)
192: {
193: return (ctx->c0 << 8) | ctx->c1;
194: }
195:
196: #endif
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>