Annotation of embedaddon/quagga/tests/test-checksum.c, revision 1.1.1.2

1.1       misho       1: #include <zebra.h>
                      2: #include <stdlib.h>
                      3: #include <time.h>
                      4: 
                      5: #include "checksum.h"
                      6: 
                      7: struct thread_master *master;
                      8: 
                      9: struct acc_vals {
                     10:   int c0;
                     11:   int c1;
                     12: };
                     13: 
                     14: struct csum_vals {
                     15:   struct acc_vals a;
                     16:   int x; 
                     17:   int y;
                     18: };
                     19: 
                     20: static struct csum_vals ospfd_vals, isisd_vals;
                     21: 
                     22: typedef size_t testsz_t;
                     23: typedef uint16_t testoff_t;
                     24: 
                     25: /* Fletcher Checksum -- Refer to RFC1008. */
                     26: #define MODX                 4102
                     27: 
                     28: /* Accumulator phase of checksum */
                     29: static 
                     30: struct acc_vals
                     31: accumulate (u_char *buffer, testsz_t len, testoff_t off)
                     32: {
                     33:   u_int8_t *p;
                     34:   u_int16_t *csum;
1.1.1.2 ! misho      35:   int i, partial_len;
1.1       misho      36:   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;
                     44:   
                     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:  */
                     66: static u_int16_t 
                     67: reduce_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 */
                     91: static u_int16_t 
                     92: reduce_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 */
                    115: static u_int16_t 
                    116: reduce_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? */
                    150: static u_int16_t 
                    151: reduce_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 */
                    185: static u_int16_t 
                    186: reduce_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 */
                    220: static u_int16_t 
                    221: reduce_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: 
                    254: struct 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 */
                    268: static u_int16_t
                    269: ospfd_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 */
                    322: static u_int16_t
                    323: iso_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: 
                    393: static int
                    394: verify (u_char * buffer, testsz_t len)
                    395: {
                    396:   u_int8_t *p;
                    397:   u_int32_t c0;
                    398:   u_int32_t c1;
                    399:   int i, partial_len;
                    400:  
                    401:   p = buffer;
                    402: 
                    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: 
1.1.1.2 ! misho     427: static int  /* return checksum in low-order 16 bits */
1.1       misho     428: in_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: 
1.1.1.2 ! misho     459: static int /* return checksum in low-order 16 bits */
1.1       misho     460: in_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: 
                    486: int
                    487: main(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) {
                    499:     u_int16_t ospfd, isisd, lib, in_csum, in_csum_res, in_csum_rfc;
                    500:     int i,j;
                    501: 
                    502:     exercise += EXERCISESTEP;
                    503:     exercise %= MAXDATALEN;
                    504:     
                    505:     for (i = 0; i < exercise; i += sizeof (long int)) {
                    506:       long int rand = random ();
                    507:       
                    508:       for (j = sizeof (long int); j > 0; j--)
                    509:         buffer[i + (sizeof (long int) - j)] = (rand >> (j * 8)) & 0xff;
                    510:     }
                    511:     
                    512:     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: 
                    520:     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");
                    545:         for (i = 0; reducts[i].name != NULL; i++) {    
                    546:           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  ");
                    555:       for (i = 0; i < exercise; i++) {
                    556:         printf ("0x%02x,%s",
                    557:                 buffer[i],
                    558:                 (i + 1) % 8 ? " " : "\n  ");
                    559:       }
                    560:       printf ("\n}\n");
                    561:       exit (1);
                    562:     }
                    563:   }
                    564: }

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