ospfd: Discriminate better when selecting links between vertices in SPF
[jleu-quagga.git] / tests / test-checksum.c
blobbd156baa1c816a062de7066b8b08df86d545b832
1 #include <zebra.h>
2 #include <stdlib.h>
3 #include <time.h>
5 #include "checksum.h"
7 struct thread_master *master;
9 struct acc_vals {
10 int c0;
11 int c1;
14 struct csum_vals {
15 struct acc_vals a;
16 int x;
17 int y;
20 static struct csum_vals ospfd_vals, isisd_vals;
22 typedef size_t testsz_t;
23 typedef uint16_t testoff_t;
25 /* Fletcher Checksum -- Refer to RFC1008. */
26 #define MODX 4102
28 /* Accumulator phase of checksum */
29 static
30 struct acc_vals
31 accumulate (u_char *buffer, testsz_t len, testoff_t off)
33 u_int8_t *p;
34 u_int16_t *csum;
35 int i, init_len, partial_len;
36 struct acc_vals ret;
38 csum = (u_int16_t *) (buffer + off);
39 *(csum) = 0;
41 p = buffer;
42 ret.c0 = 0;
43 ret.c1 = 0;
44 init_len = len;
46 while (len != 0)
48 partial_len = MIN(len, MODX);
50 for (i = 0; i < partial_len; i++)
52 ret.c0 = ret.c0 + *(p++);
53 ret.c1 += ret.c0;
56 ret.c0 = ret.c0 % 255;
57 ret.c1 = ret.c1 % 255;
59 len -= partial_len;
61 return ret;
64 /* The final reduction phase.
65 * This one should be the original ospfd version
67 static u_int16_t
68 reduce_ospfd (struct csum_vals *vals, testsz_t len, testoff_t off)
70 #define x vals->x
71 #define y vals->y
72 #define c0 vals->a.c0
73 #define c1 vals->a.c1
75 x = ((len - off - 1) * c0 - c1) % 255;
77 if (x <= 0)
78 x += 255;
79 y = 510 - c0 - x;
80 if (y > 255)
81 y -= 255;
83 /* take care endian issue. */
84 return htons ((x << 8) + y);
85 #undef x
86 #undef y
87 #undef c0
88 #undef c1
91 /* slightly different concatenation */
92 static u_int16_t
93 reduce_ospfd1 (struct csum_vals *vals, testsz_t len, testoff_t off)
95 #define x vals->x
96 #define y vals->y
97 #define c0 vals->a.c0
98 #define c1 vals->a.c1
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;
107 /* take care endian issue. */
108 return htons ((x << 8) | (y & 0xff));
109 #undef x
110 #undef y
111 #undef c0
112 #undef c1
115 /* original isisd version */
116 static u_int16_t
117 reduce_isisd (struct csum_vals *vals, testsz_t len, testoff_t off)
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;
125 mul = (len - off)*(c0);
126 x = mul - c0 - c1;
127 y = c1 - mul - 1;
129 if (y > 0)
130 y++;
131 if (x < 0)
132 x--;
134 x %= 255;
135 y %= 255;
137 if (x == 0)
138 x = 255;
139 if (y == 0)
140 y = 1;
142 return htons ((x << 8) | (y & 0xff));
144 #undef x
145 #undef y
146 #undef c0
147 #undef c1
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)
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;
160 mul = (len - off)*(c0);
161 x = mul - c0 - c1;
162 y = c1 - mul;
164 if (y > 0)
165 y++;
166 if (x < 0)
167 x--;
169 x %= 255;
170 y %= 255;
172 if (x == 0)
173 x = 255;
174 if (y == 0)
175 y = 1;
177 return htons ((x << 8) | (y & 0xff));
179 #undef x
180 #undef y
181 #undef c0
182 #undef c1
185 /* Move the mods yp */
186 static u_int16_t
187 reduce_isisd_mod (struct csum_vals *vals, testsz_t len, testoff_t off)
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;
195 mul = (len - off)*(c0);
196 x = mul - c1 - c0;
197 y = c1 - mul - 1;
199 x %= 255;
200 y %= 255;
202 if (y > 0)
203 y++;
204 if (x < 0)
205 x--;
207 if (x == 0)
208 x = 255;
209 if (y == 0)
210 y = 1;
212 return htons ((x << 8) | (y & 0xff));
214 #undef x
215 #undef y
216 #undef c0
217 #undef c1
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)
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;
230 mul = (len - off)*(c0);
231 x = mul - c0 - c1;
232 y = c1 - mul;
234 x %= 255;
235 y %= 255;
237 if (y > 0)
238 y++;
239 if (x < 0)
240 x--;
242 if (x == 0)
243 x = 255;
244 if (y == 0)
245 y = 1;
247 return htons ((x << 8) | (y & 0xff));
249 #undef x
250 #undef y
251 #undef c0
252 #undef c1
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 },
268 /* The original ospfd checksum */
269 static u_int16_t
270 ospfd_checksum (u_char *buffer, testsz_t len, testoff_t off)
272 u_char *sp, *ep, *p, *q;
273 int c0 = 0, c1 = 0;
274 int x, y;
275 u_int16_t checksum, *csum;
277 csum = (u_int16_t *) (buffer + off);
278 *(csum) = 0;
280 sp = buffer;
282 for (ep = sp + len; sp < ep; sp = q)
284 q = sp + MODX;
285 if (q > ep)
286 q = ep;
287 for (p = sp; p < q; p++)
289 c0 += *p;
290 c1 += c0;
292 c0 %= 255;
293 c1 %= 255;
296 ospfd_vals.a.c0 = c0;
297 ospfd_vals.a.c1 = c1;
299 //printf ("%s: len %u, off %u, c0 %d, c1 %d\n",
300 // __func__, len, off, c0, c1);
302 x = ((int)(len - off - 1) * (int)c0 - (int)c1) % 255;
304 if (x <= 0)
305 x += 255;
306 y = 510 - c0 - x;
307 if (y > 255)
308 y -= 255;
310 ospfd_vals.x = x;
311 ospfd_vals.y = y;
313 buffer[off] = x;
314 buffer[off + 1] = y;
316 /* take care endian issue. */
317 checksum = htons ((x << 8) | (y & 0xff));
319 return (checksum);
322 /* the original, broken isisd checksum */
323 static u_int16_t
324 iso_csum_create (u_char * buffer, testsz_t len, testoff_t off)
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;
336 checksum = 0;
338 csum = (u_int16_t *) (buffer + off);
339 *(csum) = checksum;
341 p = buffer;
342 c0 = 0;
343 c1 = 0;
344 init_len = len;
346 while (len != 0)
348 partial_len = MIN(len, MODX);
350 for (i = 0; i < partial_len; i++)
352 c0 = c0 + *(p++);
353 c1 += c0;
356 c0 = c0 % 255;
357 c1 = c1 % 255;
359 len -= partial_len;
362 isisd_vals.a.c0 = c0;
363 isisd_vals.a.c1 = c1;
365 mul = (init_len - off) * c0;
367 x = mul - c1 - c0;
368 y = c1 - mul - 1;
370 if (y > 0)
371 y++;
372 if (x < 0)
373 x--;
375 x %= 255;
376 y %= 255;
378 if (x == 0)
379 x = 255;
380 if (y == 0)
381 y = 1;
383 isisd_vals.x = x;
384 isisd_vals.y = y;
386 checksum = htons((x << 8) | (y & 0xFF));
388 *(csum) = checksum;
390 /* return the checksum for user usage */
391 return checksum;
394 static int
395 verify (u_char * buffer, testsz_t len)
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;
403 p = buffer;
404 checksum = 0;
406 c0 = 0;
407 c1 = 0;
409 while (len)
411 partial_len = MIN(len, 5803);
413 for (i = 0; i < partial_len; i++)
415 c0 = c0 + *(p++);
416 c1 += c0;
418 c0 = c0 % 255;
419 c1 = c1 % 255;
421 len -= partial_len;
424 if (c0 == 0 && c1 == 0)
425 return 0;
427 return 1;
430 int /* return checksum in low-order 16 bits */
431 in_cksum_optimized(void *parg, int nbytes)
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;
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.
443 sum = 0;
444 count = nbytes >> 1; /* div by 2 */
445 for(ptr--; count; --count)
446 sum += *++ptr;
448 if (nbytes & 1) /* Odd */
449 sum += *(u_char *)(++ptr); /* one byte only */
452 * Add back carry outs from top 16 bits to low 16 bits.
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);
462 int /* return checksum in low-order 16 bits */
463 in_cksum_rfc(void *parg, int count)
464 /* from RFC 1071 */
466 u_short *addr = parg;
467 /* Compute Internet Checksum for "count" bytes
468 * beginning at location "addr".
470 register long sum = 0;
472 while (count > 1) {
473 /* This is the inner loop */
474 sum += *addr++;
475 count -= 2;
477 /* Add left-over byte, if any */
478 if (count > 0) {
479 sum += *(u_char *)addr;
482 /* Fold 32-bit sum to 16 bits */
483 while (sum>>16)
484 sum = (sum & 0xffff) + (sum >> 16);
485 return ~sum;
490 main(int argc, char **argv)
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
499 srandom (time (NULL));
501 while (1) {
502 u_int16_t ospfd, isisd, lib, in_csum, in_csum_res, in_csum_rfc;
503 int i,j;
505 exercise += EXERCISESTEP;
506 exercise %= MAXDATALEN;
508 for (i = 0; i < exercise; i += sizeof (long int)) {
509 long int rand = random ();
511 for (j = sizeof (long int); j > 0; j--)
512 buffer[i + (sizeof (long int) - j)] = (rand >> (j * 8)) & 0xff;
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);
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");
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,
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);
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 ");
563 printf ("\n}\n");
564 exit (1);