blob: 9672e95a1413c331a8485111dedb254561e0981c [file] [log] [blame]
Paul Jakma010ebbb2014-09-16 11:53:49 +01001/*
2 * Copyright (C) 2008 Sun Microsystems, Inc.
3 *
4 * This file is part of Quagga.
5 *
6 * Quagga is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation; either version 2, or (at your option) any
9 * later version.
10 *
11 * Quagga is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with Quagga; see the file COPYING. If not, write to the Free
18 * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
19 * 02111-1307, USA.
20 */
21
Paul Jakma5d4b8cf2008-11-16 18:34:19 +000022#include <zebra.h>
23#include <stdlib.h>
24#include <time.h>
25
26#include "checksum.h"
27
28struct thread_master *master;
29
30struct acc_vals {
31 int c0;
32 int c1;
33};
34
35struct csum_vals {
36 struct acc_vals a;
37 int x;
38 int y;
39};
40
41static struct csum_vals ospfd_vals, isisd_vals;
42
43typedef size_t testsz_t;
44typedef uint16_t testoff_t;
45
46/* Fletcher Checksum -- Refer to RFC1008. */
47#define MODX 4102
David Lamparter6b0655a2014-06-04 06:53:35 +020048
Paul Jakma5d4b8cf2008-11-16 18:34:19 +000049/* Accumulator phase of checksum */
50static
51struct acc_vals
52accumulate (u_char *buffer, testsz_t len, testoff_t off)
53{
54 u_int8_t *p;
55 u_int16_t *csum;
Paul Jakma1dba2542012-05-01 16:20:33 +010056 int i, partial_len;
Paul Jakma5d4b8cf2008-11-16 18:34:19 +000057 struct acc_vals ret;
58
59 csum = (u_int16_t *) (buffer + off);
60 *(csum) = 0;
61
62 p = buffer;
63 ret.c0 = 0;
64 ret.c1 = 0;
Paul Jakma5d4b8cf2008-11-16 18:34:19 +000065
66 while (len != 0)
67 {
68 partial_len = MIN(len, MODX);
69
70 for (i = 0; i < partial_len; i++)
71 {
72 ret.c0 = ret.c0 + *(p++);
73 ret.c1 += ret.c0;
74 }
75
76 ret.c0 = ret.c0 % 255;
77 ret.c1 = ret.c1 % 255;
78
79 len -= partial_len;
80 }
81 return ret;
82}
83
84/* The final reduction phase.
85 * This one should be the original ospfd version
86 */
87static u_int16_t
88reduce_ospfd (struct csum_vals *vals, testsz_t len, testoff_t off)
89{
90#define x vals->x
91#define y vals->y
92#define c0 vals->a.c0
93#define c1 vals->a.c1
94
95 x = ((len - off - 1) * c0 - c1) % 255;
96
97 if (x <= 0)
98 x += 255;
99 y = 510 - c0 - x;
100 if (y > 255)
101 y -= 255;
102
103 /* take care endian issue. */
104 return htons ((x << 8) + y);
105#undef x
106#undef y
107#undef c0
108#undef c1
109}
110
111/* slightly different concatenation */
112static u_int16_t
113reduce_ospfd1 (struct csum_vals *vals, testsz_t len, testoff_t off)
114{
115#define x vals->x
116#define y vals->y
117#define c0 vals->a.c0
118#define c1 vals->a.c1
119
120 x = ((len - off - 1) * c0 - c1) % 255;
121 if (x <= 0)
122 x += 255;
123 y = 510 - c0 - x;
124 if (y > 255)
125 y -= 255;
126
127 /* take care endian issue. */
128 return htons ((x << 8) | (y & 0xff));
129#undef x
130#undef y
131#undef c0
132#undef c1
133}
134
135/* original isisd version */
136static u_int16_t
137reduce_isisd (struct csum_vals *vals, testsz_t len, testoff_t off)
138{
139#define x vals->x
140#define y vals->y
141#define c0 vals->a.c0
142#define c1 vals->a.c1
143 u_int32_t mul;
144
145 mul = (len - off)*(c0);
146 x = mul - c0 - c1;
147 y = c1 - mul - 1;
148
149 if (y > 0)
150 y++;
151 if (x < 0)
152 x--;
153
154 x %= 255;
155 y %= 255;
156
157 if (x == 0)
158 x = 255;
159 if (y == 0)
160 y = 1;
161
162 return htons ((x << 8) | (y & 0xff));
163
164#undef x
165#undef y
166#undef c0
167#undef c1
168}
169
170/* Is the -1 in y wrong perhaps? */
171static u_int16_t
172reduce_isisd_yfix (struct csum_vals *vals, testsz_t len, testoff_t off)
173{
174#define x vals->x
175#define y vals->y
176#define c0 vals->a.c0
177#define c1 vals->a.c1
178 u_int32_t mul;
179
180 mul = (len - off)*(c0);
181 x = mul - c0 - c1;
182 y = c1 - mul;
183
184 if (y > 0)
185 y++;
186 if (x < 0)
187 x--;
188
189 x %= 255;
190 y %= 255;
191
192 if (x == 0)
193 x = 255;
194 if (y == 0)
195 y = 1;
196
197 return htons ((x << 8) | (y & 0xff));
198
199#undef x
200#undef y
201#undef c0
202#undef c1
203}
204
205/* Move the mods yp */
206static u_int16_t
207reduce_isisd_mod (struct csum_vals *vals, testsz_t len, testoff_t off)
208{
209#define x vals->x
210#define y vals->y
211#define c0 vals->a.c0
212#define c1 vals->a.c1
213 u_int32_t mul;
214
215 mul = (len - off)*(c0);
216 x = mul - c1 - c0;
217 y = c1 - mul - 1;
218
219 x %= 255;
220 y %= 255;
221
222 if (y > 0)
223 y++;
224 if (x < 0)
225 x--;
226
227 if (x == 0)
228 x = 255;
229 if (y == 0)
230 y = 1;
231
232 return htons ((x << 8) | (y & 0xff));
233
234#undef x
235#undef y
236#undef c0
237#undef c1
238}
239
240/* Move the mods up + fix y */
241static u_int16_t
242reduce_isisd_mody (struct csum_vals *vals, testsz_t len, testoff_t off)
243{
244#define x vals->x
245#define y vals->y
246#define c0 vals->a.c0
247#define c1 vals->a.c1
248 u_int32_t mul;
249
250 mul = (len - off)*(c0);
251 x = mul - c0 - c1;
252 y = c1 - mul;
253
254 x %= 255;
255 y %= 255;
256
257 if (y > 0)
258 y++;
259 if (x < 0)
260 x--;
261
262 if (x == 0)
263 x = 255;
264 if (y == 0)
265 y = 1;
266
267 return htons ((x << 8) | (y & 0xff));
268
269#undef x
270#undef y
271#undef c0
272#undef c1
273}
274
275struct reductions_t {
276 const char *name;
277 u_int16_t (*f) (struct csum_vals *, testsz_t, testoff_t);
278} reducts[] = {
279 { .name = "ospfd", .f = reduce_ospfd },
280 { .name = "ospfd-1", .f = reduce_ospfd1 },
281 { .name = "isisd", .f = reduce_isisd },
282 { .name = "isisd-yfix", .f = reduce_isisd_yfix },
283 { .name = "isisd-mod", .f = reduce_isisd_mod },
284 { .name = "isisd-mody", .f = reduce_isisd_mody },
285 { NULL, NULL },
286};
David Lamparter6b0655a2014-06-04 06:53:35 +0200287
Paul Jakma5d4b8cf2008-11-16 18:34:19 +0000288/* The original ospfd checksum */
289static u_int16_t
290ospfd_checksum (u_char *buffer, testsz_t len, testoff_t off)
291{
292 u_char *sp, *ep, *p, *q;
293 int c0 = 0, c1 = 0;
294 int x, y;
295 u_int16_t checksum, *csum;
296
297 csum = (u_int16_t *) (buffer + off);
298 *(csum) = 0;
299
300 sp = buffer;
301
302 for (ep = sp + len; sp < ep; sp = q)
303 {
304 q = sp + MODX;
305 if (q > ep)
306 q = ep;
307 for (p = sp; p < q; p++)
308 {
309 c0 += *p;
310 c1 += c0;
311 }
312 c0 %= 255;
313 c1 %= 255;
314 }
315
316 ospfd_vals.a.c0 = c0;
317 ospfd_vals.a.c1 = c1;
318
319 //printf ("%s: len %u, off %u, c0 %d, c1 %d\n",
320 // __func__, len, off, c0, c1);
321
322 x = ((int)(len - off - 1) * (int)c0 - (int)c1) % 255;
323
324 if (x <= 0)
325 x += 255;
326 y = 510 - c0 - x;
327 if (y > 255)
328 y -= 255;
329
330 ospfd_vals.x = x;
331 ospfd_vals.y = y;
332
333 buffer[off] = x;
334 buffer[off + 1] = y;
335
336 /* take care endian issue. */
337 checksum = htons ((x << 8) | (y & 0xff));
338
339 return (checksum);
340}
341
342/* the original, broken isisd checksum */
343static u_int16_t
344iso_csum_create (u_char * buffer, testsz_t len, testoff_t off)
345{
346
347 u_int8_t *p;
348 int x;
349 int y;
350 u_int32_t mul;
351 u_int32_t c0;
352 u_int32_t c1;
353 u_int16_t checksum, *csum;
354 int i, init_len, partial_len;
355
356 checksum = 0;
357
358 csum = (u_int16_t *) (buffer + off);
359 *(csum) = checksum;
360
361 p = buffer;
362 c0 = 0;
363 c1 = 0;
364 init_len = len;
365
366 while (len != 0)
367 {
368 partial_len = MIN(len, MODX);
369
370 for (i = 0; i < partial_len; i++)
371 {
372 c0 = c0 + *(p++);
373 c1 += c0;
374 }
375
376 c0 = c0 % 255;
377 c1 = c1 % 255;
378
379 len -= partial_len;
380 }
381
382 isisd_vals.a.c0 = c0;
383 isisd_vals.a.c1 = c1;
384
385 mul = (init_len - off) * c0;
386
387 x = mul - c1 - c0;
388 y = c1 - mul - 1;
389
390 if (y > 0)
391 y++;
392 if (x < 0)
393 x--;
394
395 x %= 255;
396 y %= 255;
397
398 if (x == 0)
399 x = 255;
400 if (y == 0)
401 y = 1;
402
403 isisd_vals.x = x;
404 isisd_vals.y = y;
405
406 checksum = htons((x << 8) | (y & 0xFF));
407
408 *(csum) = checksum;
409
410 /* return the checksum for user usage */
411 return checksum;
412}
413
414static int
415verify (u_char * buffer, testsz_t len)
416{
417 u_int8_t *p;
418 u_int32_t c0;
419 u_int32_t c1;
Paul Jakma5d4b8cf2008-11-16 18:34:19 +0000420 int i, partial_len;
421
422 p = buffer;
Paul Jakma5d4b8cf2008-11-16 18:34:19 +0000423
424 c0 = 0;
425 c1 = 0;
426
427 while (len)
428 {
429 partial_len = MIN(len, 5803);
430
431 for (i = 0; i < partial_len; i++)
432 {
433 c0 = c0 + *(p++);
434 c1 += c0;
435 }
436 c0 = c0 % 255;
437 c1 = c1 % 255;
438
439 len -= partial_len;
440 }
441
442 if (c0 == 0 && c1 == 0)
443 return 0;
444
445 return 1;
446}
447
Paul Jakma1dba2542012-05-01 16:20:33 +0100448static int /* return checksum in low-order 16 bits */
Joakim Tjernlund439c52f2008-12-01 16:25:06 +0100449in_cksum_optimized(void *parg, int nbytes)
450{
451 u_short *ptr = parg;
452 register long sum; /* assumes long == 32 bits */
453 register u_short answer; /* assumes u_short == 16 bits */
454 register int count;
455 /*
456 * Our algorithm is simple, using a 32-bit accumulator (sum),
457 * we add sequential 16-bit words to it, and at the end, fold back
458 * all the carry bits from the top 16 bits into the lower 16 bits.
459 */
460
461 sum = 0;
462 count = nbytes >> 1; /* div by 2 */
463 for(ptr--; count; --count)
464 sum += *++ptr;
465
466 if (nbytes & 1) /* Odd */
467 sum += *(u_char *)(++ptr); /* one byte only */
468
469 /*
470 * Add back carry outs from top 16 bits to low 16 bits.
471 */
472
473 sum = (sum >> 16) + (sum & 0xffff); /* add high-16 to low-16 */
474 sum += (sum >> 16); /* add carry */
475 answer = ~sum; /* ones-complement, then truncate to 16 bits */
476 return(answer);
477}
478
479
Paul Jakma1dba2542012-05-01 16:20:33 +0100480static int /* return checksum in low-order 16 bits */
Joakim Tjernlund439c52f2008-12-01 16:25:06 +0100481in_cksum_rfc(void *parg, int count)
482/* from RFC 1071 */
483{
484 u_short *addr = parg;
485 /* Compute Internet Checksum for "count" bytes
486 * beginning at location "addr".
487 */
488 register long sum = 0;
489
490 while (count > 1) {
491 /* This is the inner loop */
492 sum += *addr++;
493 count -= 2;
494 }
495 /* Add left-over byte, if any */
496 if (count > 0) {
497 sum += *(u_char *)addr;
498 }
499
500 /* Fold 32-bit sum to 16 bits */
501 while (sum>>16)
502 sum = (sum & 0xffff) + (sum >> 16);
503 return ~sum;
504}
505
506
Paul Jakma5d4b8cf2008-11-16 18:34:19 +0000507int
508main(int argc, char **argv)
509{
510/* 60017 65629 702179 */
511#define MAXDATALEN 60017
512#define BUFSIZE MAXDATALEN + sizeof(u_int16_t)
513 u_char buffer[BUFSIZE];
514 int exercise = 0;
515#define EXERCISESTEP 257
516
517 srandom (time (NULL));
518
519 while (1) {
Joakim Tjernlund439c52f2008-12-01 16:25:06 +0100520 u_int16_t ospfd, isisd, lib, in_csum, in_csum_res, in_csum_rfc;
521 int i,j;
522
Paul Jakma5d4b8cf2008-11-16 18:34:19 +0000523 exercise += EXERCISESTEP;
524 exercise %= MAXDATALEN;
525
Joakim Tjernlund439c52f2008-12-01 16:25:06 +0100526 for (i = 0; i < exercise; i += sizeof (long int)) {
Paul Jakma5d4b8cf2008-11-16 18:34:19 +0000527 long int rand = random ();
528
Joakim Tjernlund439c52f2008-12-01 16:25:06 +0100529 for (j = sizeof (long int); j > 0; j--)
Paul Jakma5d4b8cf2008-11-16 18:34:19 +0000530 buffer[i + (sizeof (long int) - j)] = (rand >> (j * 8)) & 0xff;
531 }
532
Joakim Tjernlund439c52f2008-12-01 16:25:06 +0100533 in_csum = in_cksum(buffer, exercise);
534 in_csum_res = in_cksum_optimized(buffer, exercise);
535 in_csum_rfc = in_cksum_rfc(buffer, exercise);
536 if (in_csum_res != in_csum || in_csum != in_csum_rfc)
537 printf ("verify: in_chksum failed in_csum:%x, in_csum_res:%x,"
538 "in_csum_rfc %x, len:%d\n",
539 in_csum, in_csum_res, in_csum_rfc, exercise);
540
Paul Jakma5d4b8cf2008-11-16 18:34:19 +0000541 ospfd = ospfd_checksum (buffer, exercise + sizeof(u_int16_t), exercise);
542 if (verify (buffer, exercise + sizeof(u_int16_t)))
543 printf ("verify: ospfd failed\n");
544 isisd = iso_csum_create (buffer, exercise + sizeof(u_int16_t), exercise);
545 if (verify (buffer, exercise + sizeof(u_int16_t)))
546 printf ("verify: isisd failed\n");
547 lib = fletcher_checksum (buffer, exercise + sizeof(u_int16_t), exercise);
548 if (verify (buffer, exercise + sizeof(u_int16_t)))
549 printf ("verify: lib failed\n");
550
551 if (ospfd != lib) {
552 printf ("Mismatch in values at size %u\n"
553 "ospfd: 0x%04x\tc0: %d\tc1: %d\tx: %d\ty: %d\n"
554 "isisd: 0x%04x\tc0: %d\tc1: %d\tx: %d\ty: %d\n"
555 "lib: 0x%04x\n",
556 exercise,
557 ospfd, ospfd_vals.a.c0, ospfd_vals.a.c1, ospfd_vals.x, ospfd_vals.y,
558 isisd, isisd_vals.a.c0, isisd_vals.a.c1, isisd_vals.x, isisd_vals.y,
559 lib
560 );
561
562 /* Investigate reduction phase discrepencies */
563 if (ospfd_vals.a.c0 == isisd_vals.a.c0
564 && ospfd_vals.a.c1 == isisd_vals.a.c1) {
565 printf ("\n");
Joakim Tjernlund439c52f2008-12-01 16:25:06 +0100566 for (i = 0; reducts[i].name != NULL; i++) {
Paul Jakma5d4b8cf2008-11-16 18:34:19 +0000567 ospfd = reducts[i].f (&ospfd_vals,
568 exercise + sizeof (u_int16_t),
569 exercise);
570 printf ("%20s: x: %02x, y %02x, checksum 0x%04x\n",
571 reducts[i].name, ospfd_vals.x & 0xff, ospfd_vals.y & 0xff, ospfd);
572 }
573 }
574
575 printf ("\n u_char testdata [] = {\n ");
Joakim Tjernlund439c52f2008-12-01 16:25:06 +0100576 for (i = 0; i < exercise; i++) {
Paul Jakma5d4b8cf2008-11-16 18:34:19 +0000577 printf ("0x%02x,%s",
578 buffer[i],
579 (i + 1) % 8 ? " " : "\n ");
580 }
581 printf ("\n}\n");
582 exit (1);
583 }
584 }
585}