File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / quagga / tests / test-checksum.c
Revision 1.1.1.3 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Wed Nov 2 10:09:12 2016 UTC (7 years, 8 months ago) by misho
Branches: quagga, MAIN
CVS tags: v1_0_20160315, HEAD
quagga 1.0.20160315

    1: /* 
    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: 
   22: #include <zebra.h>
   23: #include <stdlib.h>
   24: #include <time.h>
   25: 
   26: #include "checksum.h"
   27: 
   28: struct thread_master *master;
   29: 
   30: struct acc_vals {
   31:   int c0;
   32:   int c1;
   33: };
   34: 
   35: struct csum_vals {
   36:   struct acc_vals a;
   37:   int x; 
   38:   int y;
   39: };
   40: 
   41: static struct csum_vals ospfd_vals, isisd_vals;
   42: 
   43: typedef size_t testsz_t;
   44: typedef uint16_t testoff_t;
   45: 
   46: /* Fletcher Checksum -- Refer to RFC1008. */
   47: #define MODX                 4102
   48: 
   49: /* The final reduction phase.
   50:  * This one should be the original ospfd version 
   51:  */
   52: static u_int16_t 
   53: reduce_ospfd (struct csum_vals *vals, testsz_t len, testoff_t off)
   54: {
   55: #define x vals->x
   56: #define y vals->y
   57: #define c0 vals->a.c0
   58: #define c1 vals->a.c1
   59: 
   60:   x = ((len - off - 1) * c0 - c1) % 255;
   61:   
   62:   if (x <= 0)
   63:     x += 255;
   64:   y = 510 - c0 - x;
   65:   if (y > 255)
   66:     y -= 255;
   67: 
   68:    /* take care endian issue. */
   69:    return htons ((x << 8) + y); 
   70: #undef x
   71: #undef y
   72: #undef c0
   73: #undef c1
   74: }
   75: 
   76: /* slightly different concatenation */
   77: static u_int16_t 
   78: reduce_ospfd1 (struct csum_vals *vals, testsz_t len, testoff_t off)
   79: {
   80: #define x vals->x
   81: #define y vals->y
   82: #define c0 vals->a.c0
   83: #define c1 vals->a.c1
   84: 
   85:   x = ((len - off - 1) * c0 - c1) % 255;
   86:   if (x <= 0)
   87:     x += 255;
   88:   y = 510 - c0 - x;
   89:   if (y > 255)
   90:     y -= 255;
   91: 
   92:    /* take care endian issue. */
   93:    return htons ((x << 8) | (y & 0xff)); 
   94: #undef x
   95: #undef y
   96: #undef c0
   97: #undef c1
   98: }
   99: 
  100: /* original isisd version */
  101: static u_int16_t 
  102: reduce_isisd (struct csum_vals *vals, testsz_t len, testoff_t off)
  103: {
  104: #define x vals->x
  105: #define y vals->y
  106: #define c0 vals->a.c0
  107: #define c1 vals->a.c1
  108:   u_int32_t mul;
  109:   
  110:   mul = (len - off)*(c0);
  111:   x = mul - c0 - c1;
  112:   y = c1 - mul - 1;
  113: 
  114:   if (y > 0)
  115:     y++;
  116:   if (x < 0)
  117:     x--;
  118: 
  119:   x %= 255;
  120:   y %= 255;
  121: 
  122:   if (x == 0)
  123:     x = 255;
  124:   if (y == 0)
  125:     y = 1;
  126: 
  127:   return htons ((x << 8) | (y & 0xff));
  128: 
  129: #undef x
  130: #undef y
  131: #undef c0
  132: #undef c1
  133: }
  134: 
  135: /* Is the -1 in y wrong perhaps? */
  136: static u_int16_t 
  137: reduce_isisd_yfix (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;
  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: /* Move the mods yp */
  171: static u_int16_t 
  172: reduce_isisd_mod (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 - c1 - c0;
  182:   y = c1 - mul - 1;
  183: 
  184:   x %= 255;
  185:   y %= 255;
  186: 
  187:   if (y > 0)
  188:     y++;
  189:   if (x < 0)
  190:     x--;
  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 up + fix y */
  206: static u_int16_t 
  207: reduce_isisd_mody (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 - c0 - c1;
  217:   y = c1 - mul;
  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: struct reductions_t {
  241:   const char *name;
  242:   u_int16_t (*f) (struct csum_vals *, testsz_t, testoff_t);
  243: } reducts[] = {
  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 },
  250:   { NULL, NULL },
  251: };
  252: 
  253: /* The original ospfd checksum */
  254: static u_int16_t
  255: ospfd_checksum (u_char *buffer, testsz_t len, testoff_t off)
  256: {
  257:   u_char *sp, *ep, *p, *q;
  258:   int c0 = 0, c1 = 0;
  259:   int x, y;
  260:   u_int16_t checksum, *csum;
  261: 
  262:   csum = (u_int16_t *) (buffer + off);
  263:   *(csum) = 0;
  264:   
  265:   sp = buffer;
  266: 
  267:   for (ep = sp + len; sp < ep; sp = q)
  268:     {
  269:       q = sp + MODX;
  270:       if (q > ep)
  271:         q = ep;
  272:       for (p = sp; p < q; p++)
  273:         {
  274:           c0 += *p;
  275:           c1 += c0;
  276:         }
  277:       c0 %= 255;
  278:       c1 %= 255;
  279:     }
  280:   
  281:   ospfd_vals.a.c0 = c0;
  282:   ospfd_vals.a.c1 = c1;
  283:   
  284:   //printf ("%s: len %u, off %u, c0 %d, c1 %d\n",
  285:   //        __func__, len, off, c0, c1);
  286: 
  287:   x = ((int)(len - off - 1) * (int)c0 - (int)c1) % 255;
  288:   
  289:   if (x <= 0)
  290:     x += 255;
  291:   y = 510 - c0 - x;
  292:   if (y > 255)
  293:     y -= 255;
  294:   
  295:   ospfd_vals.x = x;
  296:   ospfd_vals.y = y;
  297:   
  298:   buffer[off] = x;
  299:   buffer[off + 1] = y;
  300:   
  301:   /* take care endian issue. */
  302:   checksum = htons ((x << 8) | (y & 0xff));
  303: 
  304:   return (checksum);
  305: }
  306: 
  307: /* the original, broken isisd checksum */
  308: static u_int16_t
  309: iso_csum_create (u_char * buffer, testsz_t len, testoff_t off)
  310: {
  311: 
  312:   u_int8_t *p;
  313:   int x;
  314:   int y;
  315:   u_int32_t mul;
  316:   u_int32_t c0;
  317:   u_int32_t c1;
  318:   u_int16_t checksum, *csum;
  319:   int i, init_len, partial_len;
  320: 
  321:   checksum = 0;
  322:   
  323:   csum = (u_int16_t *) (buffer + off);
  324:   *(csum) = checksum;
  325:   
  326:   p = buffer;
  327:   c0 = 0;
  328:   c1 = 0;
  329:   init_len = len;
  330:   
  331:   while (len != 0)
  332:     {
  333:       partial_len = MIN(len, MODX);
  334: 
  335:       for (i = 0; i < partial_len; i++)
  336: 	{
  337: 	  c0 = c0 + *(p++);
  338: 	  c1 += c0;
  339: 	}
  340: 
  341:       c0 = c0 % 255;
  342:       c1 = c1 % 255;
  343: 
  344:       len -= partial_len;
  345:     }
  346: 
  347:   isisd_vals.a.c0 = c0;
  348:   isisd_vals.a.c1 = c1;
  349:   
  350:   mul = (init_len - off) * c0;
  351: 
  352:   x = mul - c1 - c0;
  353:   y = c1 - mul - 1;
  354: 
  355:   if (y > 0)
  356:     y++;
  357:   if (x < 0)
  358:     x--;
  359: 
  360:   x %= 255;
  361:   y %= 255;
  362: 
  363:   if (x == 0)
  364:     x = 255;
  365:   if (y == 0)
  366:     y = 1;
  367:   
  368:   isisd_vals.x = x;
  369:   isisd_vals.y = y;
  370:   
  371:   checksum = htons((x << 8) | (y & 0xFF));
  372:   
  373:   *(csum) = checksum;
  374:   
  375:   /* return the checksum for user usage */
  376:   return checksum;
  377: }
  378: 
  379: static int
  380: verify (u_char * buffer, testsz_t len)
  381: {
  382:   u_int8_t *p;
  383:   u_int32_t c0;
  384:   u_int32_t c1;
  385:   int i, partial_len;
  386:  
  387:   p = buffer;
  388: 
  389:   c0 = 0;
  390:   c1 = 0;
  391: 
  392:   while (len)
  393:     {
  394:       partial_len = MIN(len, 5803);
  395: 
  396:       for (i = 0; i < partial_len; i++)
  397:         {
  398:           c0 = c0 + *(p++);
  399:           c1 += c0;
  400:         }
  401:       c0 = c0 % 255;
  402:       c1 = c1 % 255;
  403: 
  404:       len -= partial_len;
  405:     }
  406: 
  407:   if (c0 == 0 && c1 == 0)
  408:     return 0;
  409: 
  410:   return 1;
  411: }
  412: 
  413: static int  /* return checksum in low-order 16 bits */
  414: in_cksum_optimized(void *parg, int nbytes)
  415: {
  416: 	u_short *ptr = parg;
  417: 	register long		sum;		/* assumes long == 32 bits */
  418: 	register u_short	answer;		/* assumes u_short == 16 bits */
  419: 	register int count;
  420: 	/*
  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.
  424: 	 */
  425: 
  426: 	sum = 0;
  427: 	count = nbytes >> 1; /* div by 2 */
  428: 	for(ptr--; count; --count)
  429: 	  sum += *++ptr;
  430: 
  431: 	if (nbytes & 1) /* Odd */
  432: 	  sum += *(u_char *)(++ptr);   /* one byte only */
  433: 
  434: 	/*
  435: 	 * Add back carry outs from top 16 bits to low 16 bits.
  436: 	 */
  437: 
  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 */
  441: 	return(answer);
  442: }
  443: 
  444: 
  445: static int /* return checksum in low-order 16 bits */
  446: in_cksum_rfc(void *parg, int count)
  447: /* from RFC 1071 */
  448: {
  449: 	u_short *addr = parg;
  450: 	/* Compute Internet Checksum for "count" bytes
  451: 	 *         beginning at location "addr".
  452: 	 */
  453: 	register long  sum = 0;
  454: 
  455: 	while (count > 1)  {
  456: 	  /*  This is the inner loop */
  457: 	  sum += *addr++;
  458: 	  count -= 2;
  459: 	}
  460: 	/*  Add left-over byte, if any */
  461: 	if (count > 0) {
  462: 	  sum += *(u_char *)addr;
  463: 	}
  464: 
  465: 	/*  Fold 32-bit sum to 16 bits */
  466: 	while (sum>>16)
  467:            sum = (sum & 0xffff) + (sum >> 16);
  468: 	return ~sum;
  469: }
  470: 
  471: 
  472: int
  473: main(int argc, char **argv)
  474: {
  475: /* 60017 65629 702179 */
  476: #define MAXDATALEN 60017
  477: #define BUFSIZE MAXDATALEN + sizeof(u_int16_t)
  478:   u_char buffer[BUFSIZE];
  479:   int exercise = 0;
  480: #define EXERCISESTEP 257
  481:   
  482:   srandom (time (NULL));
  483:   
  484:   while (1) {
  485:     u_int16_t ospfd, isisd, lib, in_csum, in_csum_res, in_csum_rfc;
  486:     int i,j;
  487: 
  488:     exercise += EXERCISESTEP;
  489:     exercise %= MAXDATALEN;
  490:     
  491:     for (i = 0; i < exercise; i += sizeof (long int)) {
  492:       long int rand = random ();
  493:       
  494:       for (j = sizeof (long int); j > 0; j--)
  495:         buffer[i + (sizeof (long int) - j)] = (rand >> (j * 8)) & 0xff;
  496:     }
  497:     
  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);
  505: 
  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");
  515:     
  516:     if (ospfd != lib) {
  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"
  520:               "lib: 0x%04x\n",
  521:               exercise,
  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,
  524:               lib
  525:               );
  526:       
  527:       /* Investigate reduction phase discrepencies */
  528:       if (ospfd_vals.a.c0 == isisd_vals.a.c0
  529:           && ospfd_vals.a.c1 == isisd_vals.a.c1) {
  530:         printf ("\n");
  531:         for (i = 0; reducts[i].name != NULL; i++) {	
  532:           ospfd = reducts[i].f (&ospfd_vals,
  533:                                 exercise + sizeof (u_int16_t),
  534:                                 exercise);
  535:           printf ("%20s: x: %02x, y %02x, checksum 0x%04x\n",
  536:                   reducts[i].name, ospfd_vals.x & 0xff, ospfd_vals.y & 0xff, ospfd);
  537:         }
  538:       }
  539:               
  540:       printf ("\n  u_char testdata [] = {\n  ");
  541:       for (i = 0; i < exercise; i++) {
  542:         printf ("0x%02x,%s",
  543:                 buffer[i],
  544:                 (i + 1) % 8 ? " " : "\n  ");
  545:       }
  546:       printf ("\n}\n");
  547:       exit (1);
  548:     }
  549:   }
  550: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>