2 * Copyright (C) 2008 Sun Microsystems, Inc.
4 * This file is part of Quagga.
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
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.
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
28 struct thread_master *master;
41 static struct csum_vals ospfd_vals, isisd_vals;
43 typedef size_t testsz_t;
44 typedef uint16_t testoff_t;
46 /* Fletcher Checksum -- Refer to RFC1008. */
49 /* The final reduction phase.
50 * This one should be the original ospfd version
53 reduce_ospfd (struct csum_vals *vals, testsz_t len, testoff_t off)
60 x = ((len - off - 1) * c0 - c1) % 255;
68 /* take care endian issue. */
69 return htons ((x << 8) + y);
76 /* slightly different concatenation */
78 reduce_ospfd1 (struct csum_vals *vals, testsz_t len, testoff_t off)
85 x = ((len - off - 1) * c0 - c1) % 255;
92 /* take care endian issue. */
93 return htons ((x << 8) | (y & 0xff));
100 /* original isisd version */
102 reduce_isisd (struct csum_vals *vals, testsz_t len, testoff_t off)
106 #define c0 vals->a.c0
107 #define c1 vals->a.c1
110 mul = (len - off)*(c0);
127 return htons ((x << 8) | (y & 0xff));
135 /* Is the -1 in y wrong perhaps? */
137 reduce_isisd_yfix (struct csum_vals *vals, testsz_t len, testoff_t off)
141 #define c0 vals->a.c0
142 #define c1 vals->a.c1
145 mul = (len - off)*(c0);
162 return htons ((x << 8) | (y & 0xff));
170 /* Move the mods yp */
172 reduce_isisd_mod (struct csum_vals *vals, testsz_t len, testoff_t off)
176 #define c0 vals->a.c0
177 #define c1 vals->a.c1
180 mul = (len - off)*(c0);
197 return htons ((x << 8) | (y & 0xff));
205 /* Move the mods up + fix y */
207 reduce_isisd_mody (struct csum_vals *vals, testsz_t len, testoff_t off)
211 #define c0 vals->a.c0
212 #define c1 vals->a.c1
215 mul = (len - off)*(c0);
232 return htons ((x << 8) | (y & 0xff));
240 struct reductions_t {
242 u_int16_t (*f) (struct csum_vals *, testsz_t, testoff_t);
244 { .name = "ospfd", .f = reduce_ospfd },
245 { .name = "ospfd-1", .f = reduce_ospfd1 },
246 { .name = "isisd", .f = reduce_isisd },
247 { .name = "isisd-yfix", .f = reduce_isisd_yfix },
248 { .name = "isisd-mod", .f = reduce_isisd_mod },
249 { .name = "isisd-mody", .f = reduce_isisd_mody },
253 /* The original ospfd checksum */
255 ospfd_checksum (u_char *buffer, testsz_t len, testoff_t off)
257 u_char *sp, *ep, *p, *q;
260 u_int16_t checksum, *csum;
262 csum = (u_int16_t *) (buffer + off);
267 for (ep = sp + len; sp < ep; sp = q)
272 for (p = sp; p < q; p++)
281 ospfd_vals.a.c0 = c0;
282 ospfd_vals.a.c1 = c1;
284 //printf ("%s: len %u, off %u, c0 %d, c1 %d\n",
285 // __func__, len, off, c0, c1);
287 x = ((int)(len - off - 1) * (int)c0 - (int)c1) % 255;
301 /* take care endian issue. */
302 checksum = htons ((x << 8) | (y & 0xff));
307 /* the original, broken isisd checksum */
309 iso_csum_create (u_char * buffer, testsz_t len, testoff_t off)
318 u_int16_t checksum, *csum;
319 int i, init_len, partial_len;
323 csum = (u_int16_t *) (buffer + off);
333 partial_len = MIN(len, MODX);
335 for (i = 0; i < partial_len; i++)
347 isisd_vals.a.c0 = c0;
348 isisd_vals.a.c1 = c1;
350 mul = (init_len - off) * c0;
371 checksum = htons((x << 8) | (y & 0xFF));
375 /* return the checksum for user usage */
380 verify (u_char * buffer, testsz_t len)
394 partial_len = MIN(len, 5803);
396 for (i = 0; i < partial_len; i++)
407 if (c0 == 0 && c1 == 0)
413 static int /* return checksum in low-order 16 bits */
414 in_cksum_optimized(void *parg, int nbytes)
417 register long sum; /* assumes long == 32 bits */
418 register u_short answer; /* assumes u_short == 16 bits */
421 * Our algorithm is simple, using a 32-bit accumulator (sum),
422 * we add sequential 16-bit words to it, and at the end, fold back
423 * all the carry bits from the top 16 bits into the lower 16 bits.
427 count = nbytes >> 1; /* div by 2 */
428 for(ptr--; count; --count)
431 if (nbytes & 1) /* Odd */
432 sum += *(u_char *)(++ptr); /* one byte only */
435 * Add back carry outs from top 16 bits to low 16 bits.
438 sum = (sum >> 16) + (sum & 0xffff); /* add high-16 to low-16 */
439 sum += (sum >> 16); /* add carry */
440 answer = ~sum; /* ones-complement, then truncate to 16 bits */
445 static int /* return checksum in low-order 16 bits */
446 in_cksum_rfc(void *parg, int count)
449 u_short *addr = parg;
450 /* Compute Internet Checksum for "count" bytes
451 * beginning at location "addr".
453 register long sum = 0;
456 /* This is the inner loop */
460 /* Add left-over byte, if any */
462 sum += *(u_char *)addr;
465 /* Fold 32-bit sum to 16 bits */
467 sum = (sum & 0xffff) + (sum >> 16);
473 main(int argc, char **argv)
475 /* 60017 65629 702179 */
476 #define MAXDATALEN 60017
477 #define BUFSIZE MAXDATALEN + sizeof(u_int16_t)
478 u_char buffer[BUFSIZE];
480 #define EXERCISESTEP 257
482 srandom (time (NULL));
485 u_int16_t ospfd, isisd, lib, in_csum, in_csum_res, in_csum_rfc;
488 exercise += EXERCISESTEP;
489 exercise %= MAXDATALEN;
491 for (i = 0; i < exercise; i += sizeof (long int)) {
492 long int rand = random ();
494 for (j = sizeof (long int); j > 0; j--)
495 buffer[i + (sizeof (long int) - j)] = (rand >> (j * 8)) & 0xff;
498 in_csum = in_cksum(buffer, exercise);
499 in_csum_res = in_cksum_optimized(buffer, exercise);
500 in_csum_rfc = in_cksum_rfc(buffer, exercise);
501 if (in_csum_res != in_csum || in_csum != in_csum_rfc)
502 printf ("verify: in_chksum failed in_csum:%x, in_csum_res:%x,"
503 "in_csum_rfc %x, len:%d\n",
504 in_csum, in_csum_res, in_csum_rfc, exercise);
506 ospfd = ospfd_checksum (buffer, exercise + sizeof(u_int16_t), exercise);
507 if (verify (buffer, exercise + sizeof(u_int16_t)))
508 printf ("verify: ospfd failed\n");
509 isisd = iso_csum_create (buffer, exercise + sizeof(u_int16_t), exercise);
510 if (verify (buffer, exercise + sizeof(u_int16_t)))
511 printf ("verify: isisd failed\n");
512 lib = fletcher_checksum (buffer, exercise + sizeof(u_int16_t), exercise);
513 if (verify (buffer, exercise + sizeof(u_int16_t)))
514 printf ("verify: lib failed\n");
517 printf ("Mismatch in values at size %u\n"
518 "ospfd: 0x%04x\tc0: %d\tc1: %d\tx: %d\ty: %d\n"
519 "isisd: 0x%04x\tc0: %d\tc1: %d\tx: %d\ty: %d\n"
522 ospfd, ospfd_vals.a.c0, ospfd_vals.a.c1, ospfd_vals.x, ospfd_vals.y,
523 isisd, isisd_vals.a.c0, isisd_vals.a.c1, isisd_vals.x, isisd_vals.y,
527 /* Investigate reduction phase discrepencies */
528 if (ospfd_vals.a.c0 == isisd_vals.a.c0
529 && ospfd_vals.a.c1 == isisd_vals.a.c1) {
531 for (i = 0; reducts[i].name != NULL; i++) {
532 ospfd = reducts[i].f (&ospfd_vals,
533 exercise + sizeof (u_int16_t),
535 printf ("%20s: x: %02x, y %02x, checksum 0x%04x\n",
536 reducts[i].name, ospfd_vals.x & 0xff, ospfd_vals.y & 0xff, ospfd);
540 printf ("\n u_char testdata [] = {\n ");
541 for (i = 0; i < exercise; i++) {
544 (i + 1) % 8 ? " " : "\n ");