]>
git.proxmox.com Git - mirror_frr.git/blob - tests/lib/test_checksum.c
2 * Copyright (C) 2008 Sun Microsystems, Inc.
4 * This file is part of Quagga.
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
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.
16 * You should have received a copy of the GNU General Public License along
17 * with this program; see the file COPYING; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
27 struct thread_master
*master
;
40 static struct csum_vals ospfd_vals
, isisd_vals
;
42 typedef size_t testsz_t
;
43 typedef uint16_t testoff_t
;
45 /* Fletcher Checksum -- Refer to RFC1008. */
48 /* The final reduction phase.
49 * This one should be the original ospfd version
52 reduce_ospfd (struct csum_vals
*vals
, testsz_t len
, testoff_t off
)
59 x
= ((len
- off
- 1) * c0
- c1
) % 255;
67 /* take care endian issue. */
68 return htons ((x
<< 8) + y
);
75 /* slightly different concatenation */
77 reduce_ospfd1 (struct csum_vals
*vals
, testsz_t len
, testoff_t off
)
84 x
= ((len
- off
- 1) * c0
- c1
) % 255;
91 /* take care endian issue. */
92 return htons ((x
<< 8) | (y
& 0xff));
99 /* original isisd version */
101 reduce_isisd (struct csum_vals
*vals
, testsz_t len
, testoff_t off
)
105 #define c0 vals->a.c0
106 #define c1 vals->a.c1
109 mul
= (len
- off
)*(c0
);
126 return htons ((x
<< 8) | (y
& 0xff));
134 /* Is the -1 in y wrong perhaps? */
136 reduce_isisd_yfix (struct csum_vals
*vals
, testsz_t len
, testoff_t off
)
140 #define c0 vals->a.c0
141 #define c1 vals->a.c1
144 mul
= (len
- off
)*(c0
);
161 return htons ((x
<< 8) | (y
& 0xff));
169 /* Move the mods yp */
171 reduce_isisd_mod (struct csum_vals
*vals
, testsz_t len
, testoff_t off
)
175 #define c0 vals->a.c0
176 #define c1 vals->a.c1
179 mul
= (len
- off
)*(c0
);
196 return htons ((x
<< 8) | (y
& 0xff));
204 /* Move the mods up + fix y */
206 reduce_isisd_mody (struct csum_vals
*vals
, testsz_t len
, testoff_t off
)
210 #define c0 vals->a.c0
211 #define c1 vals->a.c1
214 mul
= (len
- off
)*(c0
);
231 return htons ((x
<< 8) | (y
& 0xff));
239 struct reductions_t
{
241 u_int16_t (*f
) (struct csum_vals
*, testsz_t
, testoff_t
);
243 { .name
= "ospfd", .f
= reduce_ospfd
},
244 { .name
= "ospfd-1", .f
= reduce_ospfd1
},
245 { .name
= "isisd", .f
= reduce_isisd
},
246 { .name
= "isisd-yfix", .f
= reduce_isisd_yfix
},
247 { .name
= "isisd-mod", .f
= reduce_isisd_mod
},
248 { .name
= "isisd-mody", .f
= reduce_isisd_mody
},
252 /* The original ospfd checksum */
254 ospfd_checksum (u_char
*buffer
, testsz_t len
, testoff_t off
)
256 u_char
*sp
, *ep
, *p
, *q
;
259 u_int16_t checksum
, *csum
;
261 csum
= (u_int16_t
*) (buffer
+ off
);
266 for (ep
= sp
+ len
; sp
< ep
; sp
= q
)
271 for (p
= sp
; p
< q
; p
++)
280 ospfd_vals
.a
.c0
= c0
;
281 ospfd_vals
.a
.c1
= c1
;
283 //printf ("%s: len %u, off %u, c0 %d, c1 %d\n",
284 // __func__, len, off, c0, c1);
286 x
= ((int)(len
- off
- 1) * (int)c0
- (int)c1
) % 255;
300 /* take care endian issue. */
301 checksum
= htons ((x
<< 8) | (y
& 0xff));
306 /* the original, broken isisd checksum */
308 iso_csum_create (u_char
* buffer
, testsz_t len
, testoff_t off
)
317 u_int16_t checksum
, *csum
;
318 int i
, init_len
, partial_len
;
322 csum
= (u_int16_t
*) (buffer
+ off
);
332 partial_len
= MIN(len
, MODX
);
334 for (i
= 0; i
< partial_len
; i
++)
346 isisd_vals
.a
.c0
= c0
;
347 isisd_vals
.a
.c1
= c1
;
349 mul
= (init_len
- off
) * c0
;
370 checksum
= htons((x
<< 8) | (y
& 0xFF));
374 /* return the checksum for user usage */
379 verify (u_char
* buffer
, testsz_t len
)
393 partial_len
= MIN(len
, 5803U);
395 for (i
= 0; i
< partial_len
; i
++)
406 if (c0
== 0 && c1
== 0)
412 static int /* return checksum in low-order 16 bits */
413 in_cksum_optimized(void *parg
, int nbytes
)
416 register long sum
; /* assumes long == 32 bits */
417 register u_short answer
; /* assumes u_short == 16 bits */
420 * Our algorithm is simple, using a 32-bit accumulator (sum),
421 * we add sequential 16-bit words to it, and at the end, fold back
422 * all the carry bits from the top 16 bits into the lower 16 bits.
426 count
= nbytes
>> 1; /* div by 2 */
427 for(ptr
--; count
; --count
)
430 if (nbytes
& 1) /* Odd */
431 sum
+= *(u_char
*)(++ptr
); /* one byte only */
434 * Add back carry outs from top 16 bits to low 16 bits.
437 sum
= (sum
>> 16) + (sum
& 0xffff); /* add high-16 to low-16 */
438 sum
+= (sum
>> 16); /* add carry */
439 answer
= ~sum
; /* ones-complement, then truncate to 16 bits */
444 static int /* return checksum in low-order 16 bits */
445 in_cksum_rfc(void *parg
, int count
)
448 u_short
*addr
= parg
;
449 /* Compute Internet Checksum for "count" bytes
450 * beginning at location "addr".
452 register long sum
= 0;
455 /* This is the inner loop */
459 /* Add left-over byte, if any */
461 sum
+= *(u_char
*)addr
;
464 /* Fold 32-bit sum to 16 bits */
466 sum
= (sum
& 0xffff) + (sum
>> 16);
472 main(int argc
, char **argv
)
474 /* 60017 65629 702179 */
475 #define MAXDATALEN 60017
476 #define BUFSIZE MAXDATALEN + sizeof(u_int16_t)
477 u_char buffer
[BUFSIZE
];
479 #define EXERCISESTEP 257
481 srandom (time (NULL
));
484 u_int16_t ospfd
, isisd
, lib
, in_csum
, in_csum_res
, in_csum_rfc
;
487 exercise
+= EXERCISESTEP
;
488 exercise
%= MAXDATALEN
;
490 for (i
= 0; i
< exercise
; i
+= sizeof (long int)) {
491 long int rand
= random ();
493 for (j
= sizeof (long int); j
> 0; j
--)
494 buffer
[i
+ (sizeof (long int) - j
)] = (rand
>> (j
* 8)) & 0xff;
497 in_csum
= in_cksum(buffer
, exercise
);
498 in_csum_res
= in_cksum_optimized(buffer
, exercise
);
499 in_csum_rfc
= in_cksum_rfc(buffer
, exercise
);
500 if (in_csum_res
!= in_csum
|| in_csum
!= in_csum_rfc
)
501 printf ("verify: in_chksum failed in_csum:%x, in_csum_res:%x,"
502 "in_csum_rfc %x, len:%d\n",
503 in_csum
, in_csum_res
, in_csum_rfc
, exercise
);
505 ospfd
= ospfd_checksum (buffer
, exercise
+ sizeof(u_int16_t
), exercise
);
506 if (verify (buffer
, exercise
+ sizeof(u_int16_t
)))
507 printf ("verify: ospfd failed\n");
508 isisd
= iso_csum_create (buffer
, exercise
+ sizeof(u_int16_t
), exercise
);
509 if (verify (buffer
, exercise
+ sizeof(u_int16_t
)))
510 printf ("verify: isisd failed\n");
511 lib
= fletcher_checksum (buffer
, exercise
+ sizeof(u_int16_t
), exercise
);
512 if (verify (buffer
, exercise
+ sizeof(u_int16_t
)))
513 printf ("verify: lib failed\n");
516 printf ("Mismatch in values at size %u\n"
517 "ospfd: 0x%04x\tc0: %d\tc1: %d\tx: %d\ty: %d\n"
518 "isisd: 0x%04x\tc0: %d\tc1: %d\tx: %d\ty: %d\n"
521 ospfd
, ospfd_vals
.a
.c0
, ospfd_vals
.a
.c1
, ospfd_vals
.x
, ospfd_vals
.y
,
522 isisd
, isisd_vals
.a
.c0
, isisd_vals
.a
.c1
, isisd_vals
.x
, isisd_vals
.y
,
526 /* Investigate reduction phase discrepencies */
527 if (ospfd_vals
.a
.c0
== isisd_vals
.a
.c0
528 && ospfd_vals
.a
.c1
== isisd_vals
.a
.c1
) {
530 for (i
= 0; reducts
[i
].name
!= NULL
; i
++) {
531 ospfd
= reducts
[i
].f (&ospfd_vals
,
532 exercise
+ sizeof (u_int16_t
),
534 printf ("%20s: x: %02x, y %02x, checksum 0x%04x\n",
535 reducts
[i
].name
, ospfd_vals
.x
& 0xff, ospfd_vals
.y
& 0xff, ospfd
);
539 printf ("\n u_char testdata [] = {\n ");
540 for (i
= 0; i
< exercise
; i
++) {
543 (i
+ 1) % 8 ? " " : "\n ");