Annotation of embedaddon/quagga/tests/test-checksum.c, revision 1.1.1.3
1.1.1.3 ! misho 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:
1.1 misho 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: };
1.1.1.3 ! misho 252:
1.1 misho 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:
1.1.1.2 misho 413: static int /* return checksum in low-order 16 bits */
1.1 misho 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:
1.1.1.2 misho 445: static int /* return checksum in low-order 16 bits */
1.1 misho 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>