blob: d218840d387d1b7d8f3c3b7ed312d924ff039761 [file] [log] [blame]
Paul Jakma5d4b8cf2008-11-16 18:34:19 +00001#include <zebra.h>
2#include <stdlib.h>
3#include <time.h>
4
5#include "checksum.h"
6
7struct thread_master *master;
8
9struct acc_vals {
10 int c0;
11 int c1;
12};
13
14struct csum_vals {
15 struct acc_vals a;
16 int x;
17 int y;
18};
19
20static struct csum_vals ospfd_vals, isisd_vals;
21
22typedef size_t testsz_t;
23typedef uint16_t testoff_t;
24
25/* Fletcher Checksum -- Refer to RFC1008. */
26#define MODX 4102
27
28/* Accumulator phase of checksum */
29static
30struct acc_vals
31accumulate (u_char *buffer, testsz_t len, testoff_t off)
32{
33 u_int8_t *p;
34 u_int16_t *csum;
35 int i, init_len, partial_len;
36 struct acc_vals ret;
37
38 csum = (u_int16_t *) (buffer + off);
39 *(csum) = 0;
40
41 p = buffer;
42 ret.c0 = 0;
43 ret.c1 = 0;
44 init_len = len;
45
46 while (len != 0)
47 {
48 partial_len = MIN(len, MODX);
49
50 for (i = 0; i < partial_len; i++)
51 {
52 ret.c0 = ret.c0 + *(p++);
53 ret.c1 += ret.c0;
54 }
55
56 ret.c0 = ret.c0 % 255;
57 ret.c1 = ret.c1 % 255;
58
59 len -= partial_len;
60 }
61 return ret;
62}
63
64/* The final reduction phase.
65 * This one should be the original ospfd version
66 */
67static u_int16_t
68reduce_ospfd (struct csum_vals *vals, testsz_t len, testoff_t off)
69{
70#define x vals->x
71#define y vals->y
72#define c0 vals->a.c0
73#define c1 vals->a.c1
74
75 x = ((len - off - 1) * c0 - c1) % 255;
76
77 if (x <= 0)
78 x += 255;
79 y = 510 - c0 - x;
80 if (y > 255)
81 y -= 255;
82
83 /* take care endian issue. */
84 return htons ((x << 8) + y);
85#undef x
86#undef y
87#undef c0
88#undef c1
89}
90
91/* slightly different concatenation */
92static u_int16_t
93reduce_ospfd1 (struct csum_vals *vals, testsz_t len, testoff_t off)
94{
95#define x vals->x
96#define y vals->y
97#define c0 vals->a.c0
98#define c1 vals->a.c1
99
100 x = ((len - off - 1) * c0 - c1) % 255;
101 if (x <= 0)
102 x += 255;
103 y = 510 - c0 - x;
104 if (y > 255)
105 y -= 255;
106
107 /* take care endian issue. */
108 return htons ((x << 8) | (y & 0xff));
109#undef x
110#undef y
111#undef c0
112#undef c1
113}
114
115/* original isisd version */
116static u_int16_t
117reduce_isisd (struct csum_vals *vals, testsz_t len, testoff_t off)
118{
119#define x vals->x
120#define y vals->y
121#define c0 vals->a.c0
122#define c1 vals->a.c1
123 u_int32_t mul;
124
125 mul = (len - off)*(c0);
126 x = mul - c0 - c1;
127 y = c1 - mul - 1;
128
129 if (y > 0)
130 y++;
131 if (x < 0)
132 x--;
133
134 x %= 255;
135 y %= 255;
136
137 if (x == 0)
138 x = 255;
139 if (y == 0)
140 y = 1;
141
142 return htons ((x << 8) | (y & 0xff));
143
144#undef x
145#undef y
146#undef c0
147#undef c1
148}
149
150/* Is the -1 in y wrong perhaps? */
151static u_int16_t
152reduce_isisd_yfix (struct csum_vals *vals, testsz_t len, testoff_t off)
153{
154#define x vals->x
155#define y vals->y
156#define c0 vals->a.c0
157#define c1 vals->a.c1
158 u_int32_t mul;
159
160 mul = (len - off)*(c0);
161 x = mul - c0 - c1;
162 y = c1 - mul;
163
164 if (y > 0)
165 y++;
166 if (x < 0)
167 x--;
168
169 x %= 255;
170 y %= 255;
171
172 if (x == 0)
173 x = 255;
174 if (y == 0)
175 y = 1;
176
177 return htons ((x << 8) | (y & 0xff));
178
179#undef x
180#undef y
181#undef c0
182#undef c1
183}
184
185/* Move the mods yp */
186static u_int16_t
187reduce_isisd_mod (struct csum_vals *vals, testsz_t len, testoff_t off)
188{
189#define x vals->x
190#define y vals->y
191#define c0 vals->a.c0
192#define c1 vals->a.c1
193 u_int32_t mul;
194
195 mul = (len - off)*(c0);
196 x = mul - c1 - c0;
197 y = c1 - mul - 1;
198
199 x %= 255;
200 y %= 255;
201
202 if (y > 0)
203 y++;
204 if (x < 0)
205 x--;
206
207 if (x == 0)
208 x = 255;
209 if (y == 0)
210 y = 1;
211
212 return htons ((x << 8) | (y & 0xff));
213
214#undef x
215#undef y
216#undef c0
217#undef c1
218}
219
220/* Move the mods up + fix y */
221static u_int16_t
222reduce_isisd_mody (struct csum_vals *vals, testsz_t len, testoff_t off)
223{
224#define x vals->x
225#define y vals->y
226#define c0 vals->a.c0
227#define c1 vals->a.c1
228 u_int32_t mul;
229
230 mul = (len - off)*(c0);
231 x = mul - c0 - c1;
232 y = c1 - mul;
233
234 x %= 255;
235 y %= 255;
236
237 if (y > 0)
238 y++;
239 if (x < 0)
240 x--;
241
242 if (x == 0)
243 x = 255;
244 if (y == 0)
245 y = 1;
246
247 return htons ((x << 8) | (y & 0xff));
248
249#undef x
250#undef y
251#undef c0
252#undef c1
253}
254
255struct reductions_t {
256 const char *name;
257 u_int16_t (*f) (struct csum_vals *, testsz_t, testoff_t);
258} reducts[] = {
259 { .name = "ospfd", .f = reduce_ospfd },
260 { .name = "ospfd-1", .f = reduce_ospfd1 },
261 { .name = "isisd", .f = reduce_isisd },
262 { .name = "isisd-yfix", .f = reduce_isisd_yfix },
263 { .name = "isisd-mod", .f = reduce_isisd_mod },
264 { .name = "isisd-mody", .f = reduce_isisd_mody },
265 { NULL, NULL },
266};
267
268/* The original ospfd checksum */
269static u_int16_t
270ospfd_checksum (u_char *buffer, testsz_t len, testoff_t off)
271{
272 u_char *sp, *ep, *p, *q;
273 int c0 = 0, c1 = 0;
274 int x, y;
275 u_int16_t checksum, *csum;
276
277 csum = (u_int16_t *) (buffer + off);
278 *(csum) = 0;
279
280 sp = buffer;
281
282 for (ep = sp + len; sp < ep; sp = q)
283 {
284 q = sp + MODX;
285 if (q > ep)
286 q = ep;
287 for (p = sp; p < q; p++)
288 {
289 c0 += *p;
290 c1 += c0;
291 }
292 c0 %= 255;
293 c1 %= 255;
294 }
295
296 ospfd_vals.a.c0 = c0;
297 ospfd_vals.a.c1 = c1;
298
299 //printf ("%s: len %u, off %u, c0 %d, c1 %d\n",
300 // __func__, len, off, c0, c1);
301
302 x = ((int)(len - off - 1) * (int)c0 - (int)c1) % 255;
303
304 if (x <= 0)
305 x += 255;
306 y = 510 - c0 - x;
307 if (y > 255)
308 y -= 255;
309
310 ospfd_vals.x = x;
311 ospfd_vals.y = y;
312
313 buffer[off] = x;
314 buffer[off + 1] = y;
315
316 /* take care endian issue. */
317 checksum = htons ((x << 8) | (y & 0xff));
318
319 return (checksum);
320}
321
322/* the original, broken isisd checksum */
323static u_int16_t
324iso_csum_create (u_char * buffer, testsz_t len, testoff_t off)
325{
326
327 u_int8_t *p;
328 int x;
329 int y;
330 u_int32_t mul;
331 u_int32_t c0;
332 u_int32_t c1;
333 u_int16_t checksum, *csum;
334 int i, init_len, partial_len;
335
336 checksum = 0;
337
338 csum = (u_int16_t *) (buffer + off);
339 *(csum) = checksum;
340
341 p = buffer;
342 c0 = 0;
343 c1 = 0;
344 init_len = len;
345
346 while (len != 0)
347 {
348 partial_len = MIN(len, MODX);
349
350 for (i = 0; i < partial_len; i++)
351 {
352 c0 = c0 + *(p++);
353 c1 += c0;
354 }
355
356 c0 = c0 % 255;
357 c1 = c1 % 255;
358
359 len -= partial_len;
360 }
361
362 isisd_vals.a.c0 = c0;
363 isisd_vals.a.c1 = c1;
364
365 mul = (init_len - off) * c0;
366
367 x = mul - c1 - c0;
368 y = c1 - mul - 1;
369
370 if (y > 0)
371 y++;
372 if (x < 0)
373 x--;
374
375 x %= 255;
376 y %= 255;
377
378 if (x == 0)
379 x = 255;
380 if (y == 0)
381 y = 1;
382
383 isisd_vals.x = x;
384 isisd_vals.y = y;
385
386 checksum = htons((x << 8) | (y & 0xFF));
387
388 *(csum) = checksum;
389
390 /* return the checksum for user usage */
391 return checksum;
392}
393
394static int
395verify (u_char * buffer, testsz_t len)
396{
397 u_int8_t *p;
398 u_int32_t c0;
399 u_int32_t c1;
400 u_int16_t checksum;
401 int i, partial_len;
402
403 p = buffer;
404 checksum = 0;
405
406 c0 = 0;
407 c1 = 0;
408
409 while (len)
410 {
411 partial_len = MIN(len, 5803);
412
413 for (i = 0; i < partial_len; i++)
414 {
415 c0 = c0 + *(p++);
416 c1 += c0;
417 }
418 c0 = c0 % 255;
419 c1 = c1 % 255;
420
421 len -= partial_len;
422 }
423
424 if (c0 == 0 && c1 == 0)
425 return 0;
426
427 return 1;
428}
429
430int
431main(int argc, char **argv)
432{
433/* 60017 65629 702179 */
434#define MAXDATALEN 60017
435#define BUFSIZE MAXDATALEN + sizeof(u_int16_t)
436 u_char buffer[BUFSIZE];
437 int exercise = 0;
438#define EXERCISESTEP 257
439
440 srandom (time (NULL));
441
442 while (1) {
443 u_int16_t ospfd, isisd, lib;
444
445 exercise += EXERCISESTEP;
446 exercise %= MAXDATALEN;
447
448 for (int i = 0; i < exercise; i += sizeof (long int)) {
449 long int rand = random ();
450
451 for (int j = sizeof (long int); j > 0; j--)
452 buffer[i + (sizeof (long int) - j)] = (rand >> (j * 8)) & 0xff;
453 }
454
455 ospfd = ospfd_checksum (buffer, exercise + sizeof(u_int16_t), exercise);
456 if (verify (buffer, exercise + sizeof(u_int16_t)))
457 printf ("verify: ospfd failed\n");
458 isisd = iso_csum_create (buffer, exercise + sizeof(u_int16_t), exercise);
459 if (verify (buffer, exercise + sizeof(u_int16_t)))
460 printf ("verify: isisd failed\n");
461 lib = fletcher_checksum (buffer, exercise + sizeof(u_int16_t), exercise);
462 if (verify (buffer, exercise + sizeof(u_int16_t)))
463 printf ("verify: lib failed\n");
464
465 if (ospfd != lib) {
466 printf ("Mismatch in values at size %u\n"
467 "ospfd: 0x%04x\tc0: %d\tc1: %d\tx: %d\ty: %d\n"
468 "isisd: 0x%04x\tc0: %d\tc1: %d\tx: %d\ty: %d\n"
469 "lib: 0x%04x\n",
470 exercise,
471 ospfd, ospfd_vals.a.c0, ospfd_vals.a.c1, ospfd_vals.x, ospfd_vals.y,
472 isisd, isisd_vals.a.c0, isisd_vals.a.c1, isisd_vals.x, isisd_vals.y,
473 lib
474 );
475
476 /* Investigate reduction phase discrepencies */
477 if (ospfd_vals.a.c0 == isisd_vals.a.c0
478 && ospfd_vals.a.c1 == isisd_vals.a.c1) {
479 printf ("\n");
480 for (int i = 0; reducts[i].name != NULL; i++) {
481 ospfd = reducts[i].f (&ospfd_vals,
482 exercise + sizeof (u_int16_t),
483 exercise);
484 printf ("%20s: x: %02x, y %02x, checksum 0x%04x\n",
485 reducts[i].name, ospfd_vals.x & 0xff, ospfd_vals.y & 0xff, ospfd);
486 }
487 }
488
489 printf ("\n u_char testdata [] = {\n ");
490 for (int i = 0; i < exercise; i++) {
491 printf ("0x%02x,%s",
492 buffer[i],
493 (i + 1) % 8 ? " " : "\n ");
494 }
495 printf ("\n}\n");
496 exit (1);
497 }
498 }
499}