blob: fc4eb02d09991dd6443f2c01718211862fbb4952 [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;
Paul Jakma1dba2542012-05-01 16:20:33 +010035 int i, partial_len;
Paul Jakma5d4b8cf2008-11-16 18:34:19 +000036 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;
Paul Jakma5d4b8cf2008-11-16 18:34:19 +000044
45 while (len != 0)
46 {
47 partial_len = MIN(len, MODX);
48
49 for (i = 0; i < partial_len; i++)
50 {
51 ret.c0 = ret.c0 + *(p++);
52 ret.c1 += ret.c0;
53 }
54
55 ret.c0 = ret.c0 % 255;
56 ret.c1 = ret.c1 % 255;
57
58 len -= partial_len;
59 }
60 return ret;
61}
62
63/* The final reduction phase.
64 * This one should be the original ospfd version
65 */
66static u_int16_t
67reduce_ospfd (struct csum_vals *vals, testsz_t len, testoff_t off)
68{
69#define x vals->x
70#define y vals->y
71#define c0 vals->a.c0
72#define c1 vals->a.c1
73
74 x = ((len - off - 1) * c0 - c1) % 255;
75
76 if (x <= 0)
77 x += 255;
78 y = 510 - c0 - x;
79 if (y > 255)
80 y -= 255;
81
82 /* take care endian issue. */
83 return htons ((x << 8) + y);
84#undef x
85#undef y
86#undef c0
87#undef c1
88}
89
90/* slightly different concatenation */
91static u_int16_t
92reduce_ospfd1 (struct csum_vals *vals, testsz_t len, testoff_t off)
93{
94#define x vals->x
95#define y vals->y
96#define c0 vals->a.c0
97#define c1 vals->a.c1
98
99 x = ((len - off - 1) * c0 - c1) % 255;
100 if (x <= 0)
101 x += 255;
102 y = 510 - c0 - x;
103 if (y > 255)
104 y -= 255;
105
106 /* take care endian issue. */
107 return htons ((x << 8) | (y & 0xff));
108#undef x
109#undef y
110#undef c0
111#undef c1
112}
113
114/* original isisd version */
115static u_int16_t
116reduce_isisd (struct csum_vals *vals, testsz_t len, testoff_t off)
117{
118#define x vals->x
119#define y vals->y
120#define c0 vals->a.c0
121#define c1 vals->a.c1
122 u_int32_t mul;
123
124 mul = (len - off)*(c0);
125 x = mul - c0 - c1;
126 y = c1 - mul - 1;
127
128 if (y > 0)
129 y++;
130 if (x < 0)
131 x--;
132
133 x %= 255;
134 y %= 255;
135
136 if (x == 0)
137 x = 255;
138 if (y == 0)
139 y = 1;
140
141 return htons ((x << 8) | (y & 0xff));
142
143#undef x
144#undef y
145#undef c0
146#undef c1
147}
148
149/* Is the -1 in y wrong perhaps? */
150static u_int16_t
151reduce_isisd_yfix (struct csum_vals *vals, testsz_t len, testoff_t off)
152{
153#define x vals->x
154#define y vals->y
155#define c0 vals->a.c0
156#define c1 vals->a.c1
157 u_int32_t mul;
158
159 mul = (len - off)*(c0);
160 x = mul - c0 - c1;
161 y = c1 - mul;
162
163 if (y > 0)
164 y++;
165 if (x < 0)
166 x--;
167
168 x %= 255;
169 y %= 255;
170
171 if (x == 0)
172 x = 255;
173 if (y == 0)
174 y = 1;
175
176 return htons ((x << 8) | (y & 0xff));
177
178#undef x
179#undef y
180#undef c0
181#undef c1
182}
183
184/* Move the mods yp */
185static u_int16_t
186reduce_isisd_mod (struct csum_vals *vals, testsz_t len, testoff_t off)
187{
188#define x vals->x
189#define y vals->y
190#define c0 vals->a.c0
191#define c1 vals->a.c1
192 u_int32_t mul;
193
194 mul = (len - off)*(c0);
195 x = mul - c1 - c0;
196 y = c1 - mul - 1;
197
198 x %= 255;
199 y %= 255;
200
201 if (y > 0)
202 y++;
203 if (x < 0)
204 x--;
205
206 if (x == 0)
207 x = 255;
208 if (y == 0)
209 y = 1;
210
211 return htons ((x << 8) | (y & 0xff));
212
213#undef x
214#undef y
215#undef c0
216#undef c1
217}
218
219/* Move the mods up + fix y */
220static u_int16_t
221reduce_isisd_mody (struct csum_vals *vals, testsz_t len, testoff_t off)
222{
223#define x vals->x
224#define y vals->y
225#define c0 vals->a.c0
226#define c1 vals->a.c1
227 u_int32_t mul;
228
229 mul = (len - off)*(c0);
230 x = mul - c0 - c1;
231 y = c1 - mul;
232
233 x %= 255;
234 y %= 255;
235
236 if (y > 0)
237 y++;
238 if (x < 0)
239 x--;
240
241 if (x == 0)
242 x = 255;
243 if (y == 0)
244 y = 1;
245
246 return htons ((x << 8) | (y & 0xff));
247
248#undef x
249#undef y
250#undef c0
251#undef c1
252}
253
254struct reductions_t {
255 const char *name;
256 u_int16_t (*f) (struct csum_vals *, testsz_t, testoff_t);
257} reducts[] = {
258 { .name = "ospfd", .f = reduce_ospfd },
259 { .name = "ospfd-1", .f = reduce_ospfd1 },
260 { .name = "isisd", .f = reduce_isisd },
261 { .name = "isisd-yfix", .f = reduce_isisd_yfix },
262 { .name = "isisd-mod", .f = reduce_isisd_mod },
263 { .name = "isisd-mody", .f = reduce_isisd_mody },
264 { NULL, NULL },
265};
266
267/* The original ospfd checksum */
268static u_int16_t
269ospfd_checksum (u_char *buffer, testsz_t len, testoff_t off)
270{
271 u_char *sp, *ep, *p, *q;
272 int c0 = 0, c1 = 0;
273 int x, y;
274 u_int16_t checksum, *csum;
275
276 csum = (u_int16_t *) (buffer + off);
277 *(csum) = 0;
278
279 sp = buffer;
280
281 for (ep = sp + len; sp < ep; sp = q)
282 {
283 q = sp + MODX;
284 if (q > ep)
285 q = ep;
286 for (p = sp; p < q; p++)
287 {
288 c0 += *p;
289 c1 += c0;
290 }
291 c0 %= 255;
292 c1 %= 255;
293 }
294
295 ospfd_vals.a.c0 = c0;
296 ospfd_vals.a.c1 = c1;
297
298 //printf ("%s: len %u, off %u, c0 %d, c1 %d\n",
299 // __func__, len, off, c0, c1);
300
301 x = ((int)(len - off - 1) * (int)c0 - (int)c1) % 255;
302
303 if (x <= 0)
304 x += 255;
305 y = 510 - c0 - x;
306 if (y > 255)
307 y -= 255;
308
309 ospfd_vals.x = x;
310 ospfd_vals.y = y;
311
312 buffer[off] = x;
313 buffer[off + 1] = y;
314
315 /* take care endian issue. */
316 checksum = htons ((x << 8) | (y & 0xff));
317
318 return (checksum);
319}
320
321/* the original, broken isisd checksum */
322static u_int16_t
323iso_csum_create (u_char * buffer, testsz_t len, testoff_t off)
324{
325
326 u_int8_t *p;
327 int x;
328 int y;
329 u_int32_t mul;
330 u_int32_t c0;
331 u_int32_t c1;
332 u_int16_t checksum, *csum;
333 int i, init_len, partial_len;
334
335 checksum = 0;
336
337 csum = (u_int16_t *) (buffer + off);
338 *(csum) = checksum;
339
340 p = buffer;
341 c0 = 0;
342 c1 = 0;
343 init_len = len;
344
345 while (len != 0)
346 {
347 partial_len = MIN(len, MODX);
348
349 for (i = 0; i < partial_len; i++)
350 {
351 c0 = c0 + *(p++);
352 c1 += c0;
353 }
354
355 c0 = c0 % 255;
356 c1 = c1 % 255;
357
358 len -= partial_len;
359 }
360
361 isisd_vals.a.c0 = c0;
362 isisd_vals.a.c1 = c1;
363
364 mul = (init_len - off) * c0;
365
366 x = mul - c1 - c0;
367 y = c1 - mul - 1;
368
369 if (y > 0)
370 y++;
371 if (x < 0)
372 x--;
373
374 x %= 255;
375 y %= 255;
376
377 if (x == 0)
378 x = 255;
379 if (y == 0)
380 y = 1;
381
382 isisd_vals.x = x;
383 isisd_vals.y = y;
384
385 checksum = htons((x << 8) | (y & 0xFF));
386
387 *(csum) = checksum;
388
389 /* return the checksum for user usage */
390 return checksum;
391}
392
393static int
394verify (u_char * buffer, testsz_t len)
395{
396 u_int8_t *p;
397 u_int32_t c0;
398 u_int32_t c1;
Paul Jakma5d4b8cf2008-11-16 18:34:19 +0000399 int i, partial_len;
400
401 p = buffer;
Paul Jakma5d4b8cf2008-11-16 18:34:19 +0000402
403 c0 = 0;
404 c1 = 0;
405
406 while (len)
407 {
408 partial_len = MIN(len, 5803);
409
410 for (i = 0; i < partial_len; i++)
411 {
412 c0 = c0 + *(p++);
413 c1 += c0;
414 }
415 c0 = c0 % 255;
416 c1 = c1 % 255;
417
418 len -= partial_len;
419 }
420
421 if (c0 == 0 && c1 == 0)
422 return 0;
423
424 return 1;
425}
426
Paul Jakma1dba2542012-05-01 16:20:33 +0100427static int /* return checksum in low-order 16 bits */
Joakim Tjernlund439c52f2008-12-01 16:25:06 +0100428in_cksum_optimized(void *parg, int nbytes)
429{
430 u_short *ptr = parg;
431 register long sum; /* assumes long == 32 bits */
432 register u_short answer; /* assumes u_short == 16 bits */
433 register int count;
434 /*
435 * Our algorithm is simple, using a 32-bit accumulator (sum),
436 * we add sequential 16-bit words to it, and at the end, fold back
437 * all the carry bits from the top 16 bits into the lower 16 bits.
438 */
439
440 sum = 0;
441 count = nbytes >> 1; /* div by 2 */
442 for(ptr--; count; --count)
443 sum += *++ptr;
444
445 if (nbytes & 1) /* Odd */
446 sum += *(u_char *)(++ptr); /* one byte only */
447
448 /*
449 * Add back carry outs from top 16 bits to low 16 bits.
450 */
451
452 sum = (sum >> 16) + (sum & 0xffff); /* add high-16 to low-16 */
453 sum += (sum >> 16); /* add carry */
454 answer = ~sum; /* ones-complement, then truncate to 16 bits */
455 return(answer);
456}
457
458
Paul Jakma1dba2542012-05-01 16:20:33 +0100459static int /* return checksum in low-order 16 bits */
Joakim Tjernlund439c52f2008-12-01 16:25:06 +0100460in_cksum_rfc(void *parg, int count)
461/* from RFC 1071 */
462{
463 u_short *addr = parg;
464 /* Compute Internet Checksum for "count" bytes
465 * beginning at location "addr".
466 */
467 register long sum = 0;
468
469 while (count > 1) {
470 /* This is the inner loop */
471 sum += *addr++;
472 count -= 2;
473 }
474 /* Add left-over byte, if any */
475 if (count > 0) {
476 sum += *(u_char *)addr;
477 }
478
479 /* Fold 32-bit sum to 16 bits */
480 while (sum>>16)
481 sum = (sum & 0xffff) + (sum >> 16);
482 return ~sum;
483}
484
485
Paul Jakma5d4b8cf2008-11-16 18:34:19 +0000486int
487main(int argc, char **argv)
488{
489/* 60017 65629 702179 */
490#define MAXDATALEN 60017
491#define BUFSIZE MAXDATALEN + sizeof(u_int16_t)
492 u_char buffer[BUFSIZE];
493 int exercise = 0;
494#define EXERCISESTEP 257
495
496 srandom (time (NULL));
497
498 while (1) {
Joakim Tjernlund439c52f2008-12-01 16:25:06 +0100499 u_int16_t ospfd, isisd, lib, in_csum, in_csum_res, in_csum_rfc;
500 int i,j;
501
Paul Jakma5d4b8cf2008-11-16 18:34:19 +0000502 exercise += EXERCISESTEP;
503 exercise %= MAXDATALEN;
504
Joakim Tjernlund439c52f2008-12-01 16:25:06 +0100505 for (i = 0; i < exercise; i += sizeof (long int)) {
Paul Jakma5d4b8cf2008-11-16 18:34:19 +0000506 long int rand = random ();
507
Joakim Tjernlund439c52f2008-12-01 16:25:06 +0100508 for (j = sizeof (long int); j > 0; j--)
Paul Jakma5d4b8cf2008-11-16 18:34:19 +0000509 buffer[i + (sizeof (long int) - j)] = (rand >> (j * 8)) & 0xff;
510 }
511
Joakim Tjernlund439c52f2008-12-01 16:25:06 +0100512 in_csum = in_cksum(buffer, exercise);
513 in_csum_res = in_cksum_optimized(buffer, exercise);
514 in_csum_rfc = in_cksum_rfc(buffer, exercise);
515 if (in_csum_res != in_csum || in_csum != in_csum_rfc)
516 printf ("verify: in_chksum failed in_csum:%x, in_csum_res:%x,"
517 "in_csum_rfc %x, len:%d\n",
518 in_csum, in_csum_res, in_csum_rfc, exercise);
519
Paul Jakma5d4b8cf2008-11-16 18:34:19 +0000520 ospfd = ospfd_checksum (buffer, exercise + sizeof(u_int16_t), exercise);
521 if (verify (buffer, exercise + sizeof(u_int16_t)))
522 printf ("verify: ospfd failed\n");
523 isisd = iso_csum_create (buffer, exercise + sizeof(u_int16_t), exercise);
524 if (verify (buffer, exercise + sizeof(u_int16_t)))
525 printf ("verify: isisd failed\n");
526 lib = fletcher_checksum (buffer, exercise + sizeof(u_int16_t), exercise);
527 if (verify (buffer, exercise + sizeof(u_int16_t)))
528 printf ("verify: lib failed\n");
529
530 if (ospfd != lib) {
531 printf ("Mismatch in values at size %u\n"
532 "ospfd: 0x%04x\tc0: %d\tc1: %d\tx: %d\ty: %d\n"
533 "isisd: 0x%04x\tc0: %d\tc1: %d\tx: %d\ty: %d\n"
534 "lib: 0x%04x\n",
535 exercise,
536 ospfd, ospfd_vals.a.c0, ospfd_vals.a.c1, ospfd_vals.x, ospfd_vals.y,
537 isisd, isisd_vals.a.c0, isisd_vals.a.c1, isisd_vals.x, isisd_vals.y,
538 lib
539 );
540
541 /* Investigate reduction phase discrepencies */
542 if (ospfd_vals.a.c0 == isisd_vals.a.c0
543 && ospfd_vals.a.c1 == isisd_vals.a.c1) {
544 printf ("\n");
Joakim Tjernlund439c52f2008-12-01 16:25:06 +0100545 for (i = 0; reducts[i].name != NULL; i++) {
Paul Jakma5d4b8cf2008-11-16 18:34:19 +0000546 ospfd = reducts[i].f (&ospfd_vals,
547 exercise + sizeof (u_int16_t),
548 exercise);
549 printf ("%20s: x: %02x, y %02x, checksum 0x%04x\n",
550 reducts[i].name, ospfd_vals.x & 0xff, ospfd_vals.y & 0xff, ospfd);
551 }
552 }
553
554 printf ("\n u_char testdata [] = {\n ");
Joakim Tjernlund439c52f2008-12-01 16:25:06 +0100555 for (i = 0; i < exercise; i++) {
Paul Jakma5d4b8cf2008-11-16 18:34:19 +0000556 printf ("0x%02x,%s",
557 buffer[i],
558 (i + 1) % 8 ? " " : "\n ");
559 }
560 printf ("\n}\n");
561 exit (1);
562 }
563 }
564}