Annotation of embedaddon/quagga/tests/test-checksum.c, revision 1.1.1.1
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;
35: int i, init_len, partial_len;
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: init_len = len;
45:
46: while (len != 0)
47: {
48: partial_len = MIN(len, MODX);
49:
50: for (i = 0; i < partial_len; i++)
51: {
52: ret.c0 = ret.c0 + *(p++);
53: ret.c1 += ret.c0;
54: }
55:
56: ret.c0 = ret.c0 % 255;
57: ret.c1 = ret.c1 % 255;
58:
59: len -= partial_len;
60: }
61: return ret;
62: }
63:
64: /* The final reduction phase.
65: * This one should be the original ospfd version
66: */
67: static u_int16_t
68: reduce_ospfd (struct csum_vals *vals, testsz_t len, testoff_t off)
69: {
70: #define x vals->x
71: #define y vals->y
72: #define c0 vals->a.c0
73: #define c1 vals->a.c1
74:
75: x = ((len - off - 1) * c0 - c1) % 255;
76:
77: if (x <= 0)
78: x += 255;
79: y = 510 - c0 - x;
80: if (y > 255)
81: y -= 255;
82:
83: /* take care endian issue. */
84: return htons ((x << 8) + y);
85: #undef x
86: #undef y
87: #undef c0
88: #undef c1
89: }
90:
91: /* slightly different concatenation */
92: static u_int16_t
93: reduce_ospfd1 (struct csum_vals *vals, testsz_t len, testoff_t off)
94: {
95: #define x vals->x
96: #define y vals->y
97: #define c0 vals->a.c0
98: #define c1 vals->a.c1
99:
100: x = ((len - off - 1) * c0 - c1) % 255;
101: if (x <= 0)
102: x += 255;
103: y = 510 - c0 - x;
104: if (y > 255)
105: y -= 255;
106:
107: /* take care endian issue. */
108: return htons ((x << 8) | (y & 0xff));
109: #undef x
110: #undef y
111: #undef c0
112: #undef c1
113: }
114:
115: /* original isisd version */
116: static u_int16_t
117: reduce_isisd (struct csum_vals *vals, testsz_t len, testoff_t off)
118: {
119: #define x vals->x
120: #define y vals->y
121: #define c0 vals->a.c0
122: #define c1 vals->a.c1
123: u_int32_t mul;
124:
125: mul = (len - off)*(c0);
126: x = mul - c0 - c1;
127: y = c1 - mul - 1;
128:
129: if (y > 0)
130: y++;
131: if (x < 0)
132: x--;
133:
134: x %= 255;
135: y %= 255;
136:
137: if (x == 0)
138: x = 255;
139: if (y == 0)
140: y = 1;
141:
142: return htons ((x << 8) | (y & 0xff));
143:
144: #undef x
145: #undef y
146: #undef c0
147: #undef c1
148: }
149:
150: /* Is the -1 in y wrong perhaps? */
151: static u_int16_t
152: reduce_isisd_yfix (struct csum_vals *vals, testsz_t len, testoff_t off)
153: {
154: #define x vals->x
155: #define y vals->y
156: #define c0 vals->a.c0
157: #define c1 vals->a.c1
158: u_int32_t mul;
159:
160: mul = (len - off)*(c0);
161: x = mul - c0 - c1;
162: y = c1 - mul;
163:
164: if (y > 0)
165: y++;
166: if (x < 0)
167: x--;
168:
169: x %= 255;
170: y %= 255;
171:
172: if (x == 0)
173: x = 255;
174: if (y == 0)
175: y = 1;
176:
177: return htons ((x << 8) | (y & 0xff));
178:
179: #undef x
180: #undef y
181: #undef c0
182: #undef c1
183: }
184:
185: /* Move the mods yp */
186: static u_int16_t
187: reduce_isisd_mod (struct csum_vals *vals, testsz_t len, testoff_t off)
188: {
189: #define x vals->x
190: #define y vals->y
191: #define c0 vals->a.c0
192: #define c1 vals->a.c1
193: u_int32_t mul;
194:
195: mul = (len - off)*(c0);
196: x = mul - c1 - c0;
197: y = c1 - mul - 1;
198:
199: x %= 255;
200: y %= 255;
201:
202: if (y > 0)
203: y++;
204: if (x < 0)
205: x--;
206:
207: if (x == 0)
208: x = 255;
209: if (y == 0)
210: y = 1;
211:
212: return htons ((x << 8) | (y & 0xff));
213:
214: #undef x
215: #undef y
216: #undef c0
217: #undef c1
218: }
219:
220: /* Move the mods up + fix y */
221: static u_int16_t
222: reduce_isisd_mody (struct csum_vals *vals, testsz_t len, testoff_t off)
223: {
224: #define x vals->x
225: #define y vals->y
226: #define c0 vals->a.c0
227: #define c1 vals->a.c1
228: u_int32_t mul;
229:
230: mul = (len - off)*(c0);
231: x = mul - c0 - c1;
232: y = c1 - mul;
233:
234: x %= 255;
235: y %= 255;
236:
237: if (y > 0)
238: y++;
239: if (x < 0)
240: x--;
241:
242: if (x == 0)
243: x = 255;
244: if (y == 0)
245: y = 1;
246:
247: return htons ((x << 8) | (y & 0xff));
248:
249: #undef x
250: #undef y
251: #undef c0
252: #undef c1
253: }
254:
255: struct reductions_t {
256: const char *name;
257: u_int16_t (*f) (struct csum_vals *, testsz_t, testoff_t);
258: } reducts[] = {
259: { .name = "ospfd", .f = reduce_ospfd },
260: { .name = "ospfd-1", .f = reduce_ospfd1 },
261: { .name = "isisd", .f = reduce_isisd },
262: { .name = "isisd-yfix", .f = reduce_isisd_yfix },
263: { .name = "isisd-mod", .f = reduce_isisd_mod },
264: { .name = "isisd-mody", .f = reduce_isisd_mody },
265: { NULL, NULL },
266: };
267:
268: /* The original ospfd checksum */
269: static u_int16_t
270: ospfd_checksum (u_char *buffer, testsz_t len, testoff_t off)
271: {
272: u_char *sp, *ep, *p, *q;
273: int c0 = 0, c1 = 0;
274: int x, y;
275: u_int16_t checksum, *csum;
276:
277: csum = (u_int16_t *) (buffer + off);
278: *(csum) = 0;
279:
280: sp = buffer;
281:
282: for (ep = sp + len; sp < ep; sp = q)
283: {
284: q = sp + MODX;
285: if (q > ep)
286: q = ep;
287: for (p = sp; p < q; p++)
288: {
289: c0 += *p;
290: c1 += c0;
291: }
292: c0 %= 255;
293: c1 %= 255;
294: }
295:
296: ospfd_vals.a.c0 = c0;
297: ospfd_vals.a.c1 = c1;
298:
299: //printf ("%s: len %u, off %u, c0 %d, c1 %d\n",
300: // __func__, len, off, c0, c1);
301:
302: x = ((int)(len - off - 1) * (int)c0 - (int)c1) % 255;
303:
304: if (x <= 0)
305: x += 255;
306: y = 510 - c0 - x;
307: if (y > 255)
308: y -= 255;
309:
310: ospfd_vals.x = x;
311: ospfd_vals.y = y;
312:
313: buffer[off] = x;
314: buffer[off + 1] = y;
315:
316: /* take care endian issue. */
317: checksum = htons ((x << 8) | (y & 0xff));
318:
319: return (checksum);
320: }
321:
322: /* the original, broken isisd checksum */
323: static u_int16_t
324: iso_csum_create (u_char * buffer, testsz_t len, testoff_t off)
325: {
326:
327: u_int8_t *p;
328: int x;
329: int y;
330: u_int32_t mul;
331: u_int32_t c0;
332: u_int32_t c1;
333: u_int16_t checksum, *csum;
334: int i, init_len, partial_len;
335:
336: checksum = 0;
337:
338: csum = (u_int16_t *) (buffer + off);
339: *(csum) = checksum;
340:
341: p = buffer;
342: c0 = 0;
343: c1 = 0;
344: init_len = len;
345:
346: while (len != 0)
347: {
348: partial_len = MIN(len, MODX);
349:
350: for (i = 0; i < partial_len; i++)
351: {
352: c0 = c0 + *(p++);
353: c1 += c0;
354: }
355:
356: c0 = c0 % 255;
357: c1 = c1 % 255;
358:
359: len -= partial_len;
360: }
361:
362: isisd_vals.a.c0 = c0;
363: isisd_vals.a.c1 = c1;
364:
365: mul = (init_len - off) * c0;
366:
367: x = mul - c1 - c0;
368: y = c1 - mul - 1;
369:
370: if (y > 0)
371: y++;
372: if (x < 0)
373: x--;
374:
375: x %= 255;
376: y %= 255;
377:
378: if (x == 0)
379: x = 255;
380: if (y == 0)
381: y = 1;
382:
383: isisd_vals.x = x;
384: isisd_vals.y = y;
385:
386: checksum = htons((x << 8) | (y & 0xFF));
387:
388: *(csum) = checksum;
389:
390: /* return the checksum for user usage */
391: return checksum;
392: }
393:
394: static int
395: verify (u_char * buffer, testsz_t len)
396: {
397: u_int8_t *p;
398: u_int32_t c0;
399: u_int32_t c1;
400: u_int16_t checksum;
401: int i, partial_len;
402:
403: p = buffer;
404: checksum = 0;
405:
406: c0 = 0;
407: c1 = 0;
408:
409: while (len)
410: {
411: partial_len = MIN(len, 5803);
412:
413: for (i = 0; i < partial_len; i++)
414: {
415: c0 = c0 + *(p++);
416: c1 += c0;
417: }
418: c0 = c0 % 255;
419: c1 = c1 % 255;
420:
421: len -= partial_len;
422: }
423:
424: if (c0 == 0 && c1 == 0)
425: return 0;
426:
427: return 1;
428: }
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:
489: int
490: main(int argc, char **argv)
491: {
492: /* 60017 65629 702179 */
493: #define MAXDATALEN 60017
494: #define BUFSIZE MAXDATALEN + sizeof(u_int16_t)
495: u_char buffer[BUFSIZE];
496: int exercise = 0;
497: #define EXERCISESTEP 257
498:
499: srandom (time (NULL));
500:
501: while (1) {
502: u_int16_t ospfd, isisd, lib, in_csum, in_csum_res, in_csum_rfc;
503: int i,j;
504:
505: exercise += EXERCISESTEP;
506: exercise %= MAXDATALEN;
507:
508: for (i = 0; i < exercise; i += sizeof (long int)) {
509: long int rand = random ();
510:
511: for (j = sizeof (long int); j > 0; j--)
512: buffer[i + (sizeof (long int) - j)] = (rand >> (j * 8)) & 0xff;
513: }
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:
523: ospfd = ospfd_checksum (buffer, exercise + sizeof(u_int16_t), exercise);
524: if (verify (buffer, exercise + sizeof(u_int16_t)))
525: printf ("verify: ospfd failed\n");
526: isisd = iso_csum_create (buffer, exercise + sizeof(u_int16_t), exercise);
527: if (verify (buffer, exercise + sizeof(u_int16_t)))
528: printf ("verify: isisd failed\n");
529: lib = fletcher_checksum (buffer, exercise + sizeof(u_int16_t), exercise);
530: if (verify (buffer, exercise + sizeof(u_int16_t)))
531: printf ("verify: lib failed\n");
532:
533: if (ospfd != lib) {
534: printf ("Mismatch in values at size %u\n"
535: "ospfd: 0x%04x\tc0: %d\tc1: %d\tx: %d\ty: %d\n"
536: "isisd: 0x%04x\tc0: %d\tc1: %d\tx: %d\ty: %d\n"
537: "lib: 0x%04x\n",
538: exercise,
539: ospfd, ospfd_vals.a.c0, ospfd_vals.a.c1, ospfd_vals.x, ospfd_vals.y,
540: isisd, isisd_vals.a.c0, isisd_vals.a.c1, isisd_vals.x, isisd_vals.y,
541: lib
542: );
543:
544: /* Investigate reduction phase discrepencies */
545: if (ospfd_vals.a.c0 == isisd_vals.a.c0
546: && ospfd_vals.a.c1 == isisd_vals.a.c1) {
547: printf ("\n");
548: for (i = 0; reducts[i].name != NULL; i++) {
549: ospfd = reducts[i].f (&ospfd_vals,
550: exercise + sizeof (u_int16_t),
551: exercise);
552: printf ("%20s: x: %02x, y %02x, checksum 0x%04x\n",
553: reducts[i].name, ospfd_vals.x & 0xff, ospfd_vals.y & 0xff, ospfd);
554: }
555: }
556:
557: printf ("\n u_char testdata [] = {\n ");
558: for (i = 0; i < exercise; i++) {
559: printf ("0x%02x,%s",
560: buffer[i],
561: (i + 1) % 8 ? " " : "\n ");
562: }
563: printf ("\n}\n");
564: exit (1);
565: }
566: }
567: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>