blob: b6741f305711638f8896143294ea72e8512252ab [file] [log] [blame]
Paul Jakma010ebbb2014-09-16 11:53:49 +01001/*
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
Paul Jakma5d4b8cf2008-11-16 18:34:19 +000022#include <zebra.h>
23#include <stdlib.h>
24#include <time.h>
25
26#include "checksum.h"
27
28struct thread_master *master;
29
30struct acc_vals {
31 int c0;
32 int c1;
33};
34
35struct csum_vals {
36 struct acc_vals a;
37 int x;
38 int y;
39};
40
41static struct csum_vals ospfd_vals, isisd_vals;
42
43typedef size_t testsz_t;
44typedef uint16_t testoff_t;
45
46/* Fletcher Checksum -- Refer to RFC1008. */
47#define MODX 4102
David Lamparter6b0655a2014-06-04 06:53:35 +020048
Paul Jakma5d4b8cf2008-11-16 18:34:19 +000049/* The final reduction phase.
50 * This one should be the original ospfd version
51 */
52static u_int16_t
53reduce_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 */
77static u_int16_t
78reduce_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 */
101static u_int16_t
102reduce_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? */
136static u_int16_t
137reduce_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 */
171static u_int16_t
172reduce_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 */
206static u_int16_t
207reduce_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
240struct 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};
David Lamparter6b0655a2014-06-04 06:53:35 +0200252
Paul Jakma5d4b8cf2008-11-16 18:34:19 +0000253/* The original ospfd checksum */
254static u_int16_t
255ospfd_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 */
308static u_int16_t
309iso_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
379static int
380verify (u_char * buffer, testsz_t len)
381{
382 u_int8_t *p;
383 u_int32_t c0;
384 u_int32_t c1;
Paul Jakma5d4b8cf2008-11-16 18:34:19 +0000385 int i, partial_len;
386
387 p = buffer;
Paul Jakma5d4b8cf2008-11-16 18:34:19 +0000388
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
Paul Jakma1dba2542012-05-01 16:20:33 +0100413static int /* return checksum in low-order 16 bits */
Joakim Tjernlund439c52f2008-12-01 16:25:06 +0100414in_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
Paul Jakma1dba2542012-05-01 16:20:33 +0100445static int /* return checksum in low-order 16 bits */
Joakim Tjernlund439c52f2008-12-01 16:25:06 +0100446in_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
Paul Jakma5d4b8cf2008-11-16 18:34:19 +0000472int
473main(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) {
Joakim Tjernlund439c52f2008-12-01 16:25:06 +0100485 u_int16_t ospfd, isisd, lib, in_csum, in_csum_res, in_csum_rfc;
486 int i,j;
487
Paul Jakma5d4b8cf2008-11-16 18:34:19 +0000488 exercise += EXERCISESTEP;
489 exercise %= MAXDATALEN;
490
Joakim Tjernlund439c52f2008-12-01 16:25:06 +0100491 for (i = 0; i < exercise; i += sizeof (long int)) {
Paul Jakma5d4b8cf2008-11-16 18:34:19 +0000492 long int rand = random ();
493
Joakim Tjernlund439c52f2008-12-01 16:25:06 +0100494 for (j = sizeof (long int); j > 0; j--)
Paul Jakma5d4b8cf2008-11-16 18:34:19 +0000495 buffer[i + (sizeof (long int) - j)] = (rand >> (j * 8)) & 0xff;
496 }
497
Joakim Tjernlund439c52f2008-12-01 16:25:06 +0100498 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
Paul Jakma5d4b8cf2008-11-16 18:34:19 +0000506 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");
Joakim Tjernlund439c52f2008-12-01 16:25:06 +0100531 for (i = 0; reducts[i].name != NULL; i++) {
Paul Jakma5d4b8cf2008-11-16 18:34:19 +0000532 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 ");
Joakim Tjernlund439c52f2008-12-01 16:25:06 +0100541 for (i = 0; i < exercise; i++) {
Paul Jakma5d4b8cf2008-11-16 18:34:19 +0000542 printf ("0x%02x,%s",
543 buffer[i],
544 (i + 1) % 8 ? " " : "\n ");
545 }
546 printf ("\n}\n");
547 exit (1);
548 }
549 }
550}