Commits

Joakim Tjernlund authored and Paul Jakma committed 439c52f1900
Add test for Internet checksum.

Add 2 impl. of the Internet Checksum. One new optimized nad one form RFC 1071. Turns out that the current Quagga in_cksum() is buggy. On Big Endian routers it miscalculates odd sized buffers.
No tags

tests/test-checksum.c

Modified
420 420
421 421 len -= partial_len;
422 422 }
423 423
424 424 if (c0 == 0 && c1 == 0)
425 425 return 0;
426 426
427 427 return 1;
428 428 }
429 429
430 +int /* return checksum in low-order 16 bits */
431 +in_cksum_optimized(void *parg, int nbytes)
432 +{
433 + u_short *ptr = parg;
434 + register long sum; /* assumes long == 32 bits */
435 + register u_short answer; /* assumes u_short == 16 bits */
436 + register int count;
437 + /*
438 + * Our algorithm is simple, using a 32-bit accumulator (sum),
439 + * we add sequential 16-bit words to it, and at the end, fold back
440 + * all the carry bits from the top 16 bits into the lower 16 bits.
441 + */
442 +
443 + sum = 0;
444 + count = nbytes >> 1; /* div by 2 */
445 + for(ptr--; count; --count)
446 + sum += *++ptr;
447 +
448 + if (nbytes & 1) /* Odd */
449 + sum += *(u_char *)(++ptr); /* one byte only */
450 +
451 + /*
452 + * Add back carry outs from top 16 bits to low 16 bits.
453 + */
454 +
455 + sum = (sum >> 16) + (sum & 0xffff); /* add high-16 to low-16 */
456 + sum += (sum >> 16); /* add carry */
457 + answer = ~sum; /* ones-complement, then truncate to 16 bits */
458 + return(answer);
459 +}
460 +
461 +
462 +int /* return checksum in low-order 16 bits */
463 +in_cksum_rfc(void *parg, int count)
464 +/* from RFC 1071 */
465 +{
466 + u_short *addr = parg;
467 + /* Compute Internet Checksum for "count" bytes
468 + * beginning at location "addr".
469 + */
470 + register long sum = 0;
471 +
472 + while (count > 1) {
473 + /* This is the inner loop */
474 + sum += *addr++;
475 + count -= 2;
476 + }
477 + /* Add left-over byte, if any */
478 + if (count > 0) {
479 + sum += *(u_char *)addr;
480 + }
481 +
482 + /* Fold 32-bit sum to 16 bits */
483 + while (sum>>16)
484 + sum = (sum & 0xffff) + (sum >> 16);
485 + return ~sum;
486 +}
487 +
488 +
430 489 int
431 490 main(int argc, char **argv)
432 491 {
433 492 /* 60017 65629 702179 */
434 493 #define MAXDATALEN 60017
435 494 #define BUFSIZE MAXDATALEN + sizeof(u_int16_t)
436 495 u_char buffer[BUFSIZE];
437 496 int exercise = 0;
438 497 #define EXERCISESTEP 257
439 498
440 499 srandom (time (NULL));
441 500
442 501 while (1) {
443 - u_int16_t ospfd, isisd, lib;
444 -
502 + u_int16_t ospfd, isisd, lib, in_csum, in_csum_res, in_csum_rfc;
503 + int i,j;
504 +
445 505 exercise += EXERCISESTEP;
446 506 exercise %= MAXDATALEN;
447 507
448 - for (int i = 0; i < exercise; i += sizeof (long int)) {
508 + for (i = 0; i < exercise; i += sizeof (long int)) {
449 509 long int rand = random ();
450 510
451 - for (int j = sizeof (long int); j > 0; j--)
511 + for (j = sizeof (long int); j > 0; j--)
452 512 buffer[i + (sizeof (long int) - j)] = (rand >> (j * 8)) & 0xff;
453 513 }
454 514
515 + in_csum = in_cksum(buffer, exercise);
516 + in_csum_res = in_cksum_optimized(buffer, exercise);
517 + in_csum_rfc = in_cksum_rfc(buffer, exercise);
518 + if (in_csum_res != in_csum || in_csum != in_csum_rfc)
519 + printf ("verify: in_chksum failed in_csum:%x, in_csum_res:%x,"
520 + "in_csum_rfc %x, len:%d\n",
521 + in_csum, in_csum_res, in_csum_rfc, exercise);
522 +
455 523 ospfd = ospfd_checksum (buffer, exercise + sizeof(u_int16_t), exercise);
456 524 if (verify (buffer, exercise + sizeof(u_int16_t)))
457 525 printf ("verify: ospfd failed\n");
458 526 isisd = iso_csum_create (buffer, exercise + sizeof(u_int16_t), exercise);
459 527 if (verify (buffer, exercise + sizeof(u_int16_t)))
460 528 printf ("verify: isisd failed\n");
461 529 lib = fletcher_checksum (buffer, exercise + sizeof(u_int16_t), exercise);
462 530 if (verify (buffer, exercise + sizeof(u_int16_t)))
463 531 printf ("verify: lib failed\n");
464 532
470 538 exercise,
471 539 ospfd, ospfd_vals.a.c0, ospfd_vals.a.c1, ospfd_vals.x, ospfd_vals.y,
472 540 isisd, isisd_vals.a.c0, isisd_vals.a.c1, isisd_vals.x, isisd_vals.y,
473 541 lib
474 542 );
475 543
476 544 /* Investigate reduction phase discrepencies */
477 545 if (ospfd_vals.a.c0 == isisd_vals.a.c0
478 546 && ospfd_vals.a.c1 == isisd_vals.a.c1) {
479 547 printf ("\n");
480 - for (int i = 0; reducts[i].name != NULL; i++) {
548 + for (i = 0; reducts[i].name != NULL; i++) {
481 549 ospfd = reducts[i].f (&ospfd_vals,
482 550 exercise + sizeof (u_int16_t),
483 551 exercise);
484 552 printf ("%20s: x: %02x, y %02x, checksum 0x%04x\n",
485 553 reducts[i].name, ospfd_vals.x & 0xff, ospfd_vals.y & 0xff, ospfd);
486 554 }
487 555 }
488 556
489 557 printf ("\n u_char testdata [] = {\n ");
490 - for (int i = 0; i < exercise; i++) {
558 + for (i = 0; i < exercise; i++) {
491 559 printf ("0x%02x,%s",
492 560 buffer[i],
493 561 (i + 1) % 8 ? " " : "\n ");
494 562 }
495 563 printf ("\n}\n");
496 564 exit (1);
497 565 }
498 566 }
499 567 }

Everything looks good. We'll let you know here if there's anything you should know about.

Add shortcut