1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * Copyright (C) 2008 Sun Microsystems, Inc.
14 struct thread_master
*master
;
27 static struct csum_vals ospfd_vals
, isisd_vals
;
29 typedef size_t testsz_t
;
30 typedef uint16_t testoff_t
;
32 /* Fletcher Checksum -- Refer to RFC1008. */
35 /* The final reduction phase.
36 * This one should be the original ospfd version
38 static uint16_t reduce_ospfd(struct csum_vals
*vals
, testsz_t len
,
46 x
= ((len
- off
- 1) * c0
- c1
) % 255;
54 /* take care endian issue. */
55 return htons((x
<< 8) + y
);
62 /* slightly different concatenation */
63 static uint16_t reduce_ospfd1(struct csum_vals
*vals
, testsz_t len
,
71 x
= ((len
- off
- 1) * c0
- c1
) % 255;
78 /* take care endian issue. */
79 return htons((x
<< 8) | (y
& 0xff));
86 /* original isisd version */
87 static uint16_t reduce_isisd(struct csum_vals
*vals
, testsz_t len
,
96 mul
= (len
- off
) * (c0
);
113 return htons((x
<< 8) | (y
& 0xff));
121 /* Is the -1 in y wrong perhaps? */
122 static uint16_t reduce_isisd_yfix(struct csum_vals
*vals
, testsz_t len
,
127 #define c0 vals->a.c0
128 #define c1 vals->a.c1
131 mul
= (len
- off
) * (c0
);
148 return htons((x
<< 8) | (y
& 0xff));
156 /* Move the mods yp */
157 static uint16_t reduce_isisd_mod(struct csum_vals
*vals
, testsz_t len
,
162 #define c0 vals->a.c0
163 #define c1 vals->a.c1
166 mul
= (len
- off
) * (c0
);
183 return htons((x
<< 8) | (y
& 0xff));
191 /* Move the mods up + fix y */
192 static uint16_t reduce_isisd_mody(struct csum_vals
*vals
, testsz_t len
,
197 #define c0 vals->a.c0
198 #define c1 vals->a.c1
201 mul
= (len
- off
) * (c0
);
218 return htons((x
<< 8) | (y
& 0xff));
226 struct reductions_t
{
228 uint16_t (*f
)(struct csum_vals
*, testsz_t
, testoff_t
);
230 {.name
= "ospfd", .f
= reduce_ospfd
},
231 {.name
= "ospfd-1", .f
= reduce_ospfd1
},
232 {.name
= "isisd", .f
= reduce_isisd
},
233 {.name
= "isisd-yfix", .f
= reduce_isisd_yfix
},
234 {.name
= "isisd-mod", .f
= reduce_isisd_mod
},
235 {.name
= "isisd-mody", .f
= reduce_isisd_mody
},
239 /* The original ospfd checksum */
240 static uint16_t ospfd_checksum(uint8_t *buffer
, testsz_t len
, testoff_t off
)
242 uint8_t *sp
, *ep
, *p
, *q
;
245 uint16_t checksum
, *csum
;
247 csum
= (uint16_t *)(buffer
+ off
);
252 for (ep
= sp
+ len
; sp
< ep
; sp
= q
) {
256 for (p
= sp
; p
< q
; p
++) {
264 ospfd_vals
.a
.c0
= c0
;
265 ospfd_vals
.a
.c1
= c1
;
267 // printf ("%s: len %u, off %u, c0 %d, c1 %d\n",
268 // __func__, len, off, c0, c1);
270 x
= ((int)(len
- off
- 1) * (int)c0
- (int)c1
) % 255;
284 /* take care endian issue. */
285 checksum
= htons((x
<< 8) | (y
& 0xff));
290 /* the original, broken isisd checksum */
291 static uint16_t iso_csum_create(uint8_t *buffer
, testsz_t len
, testoff_t off
)
300 uint16_t checksum
, *csum
;
301 int i
, init_len
, partial_len
;
305 csum
= (uint16_t *)(buffer
+ off
);
314 partial_len
= MIN(len
, MODX
);
316 for (i
= 0; i
< partial_len
; i
++) {
327 isisd_vals
.a
.c0
= c0
;
328 isisd_vals
.a
.c1
= c1
;
330 mul
= (init_len
- off
) * c0
;
351 checksum
= htons((x
<< 8) | (y
& 0xFF));
355 /* return the checksum for user usage */
359 static int verify(uint8_t *buffer
, testsz_t len
)
372 partial_len
= MIN(len
, 5803U);
374 for (i
= 0; i
< partial_len
; i
++) {
384 if (c0
== 0 && c1
== 0)
390 static int /* return checksum in low-order 16 bits */
391 in_cksum_optimized(void *parg
, int nbytes
)
393 unsigned short *ptr
= parg
;
394 register long sum
; /* assumes long == 32 bits */
395 register unsigned short answer
; /* assumes unsigned short == 16 bits */
398 * Our algorithm is simple, using a 32-bit accumulator (sum),
399 * we add sequential 16-bit words to it, and at the end, fold back
400 * all the carry bits from the top 16 bits into the lower 16 bits.
404 count
= nbytes
>> 1; /* div by 2 */
405 for (ptr
--; count
; --count
)
408 if (nbytes
& 1) /* Odd */
409 sum
+= *(uint8_t *)(++ptr
); /* one byte only */
412 * Add back carry outs from top 16 bits to low 16 bits.
415 sum
= (sum
>> 16) + (sum
& 0xffff); /* add high-16 to low-16 */
416 sum
+= (sum
>> 16); /* add carry */
417 answer
= ~sum
; /* ones-complement, then truncate to 16 bits */
422 static int /* return checksum in low-order 16 bits */
423 in_cksum_rfc(void *parg
, int count
)
426 unsigned short *addr
= parg
;
427 /* Compute Internet Checksum for "count" bytes
428 * beginning at location "addr".
430 register long sum
= 0;
433 /* This is the inner loop */
437 /* Add left-over byte, if any */
439 sum
+= *(uint8_t *)addr
;
442 /* Fold 32-bit sum to 16 bits */
444 sum
= (sum
& 0xffff) + (sum
>> 16);
449 int main(int argc
, char **argv
)
451 /* 60017 65629 702179 */
452 #define MAXDATALEN 60017
453 #define BUFSIZE MAXDATALEN + sizeof(uint16_t)
454 uint8_t buffer
[BUFSIZE
];
456 #define EXERCISESTEP 257
457 struct prng
*prng
= prng_new(0);
460 uint16_t ospfd
, isisd
, lib
, in_csum
, in_csum_res
, in_csum_rfc
;
463 exercise
+= EXERCISESTEP
;
464 exercise
%= MAXDATALEN
;
466 printf("\rexercising length %d\033[K", exercise
);
468 for (i
= 0; i
< exercise
; i
++)
469 buffer
[i
] = prng_rand(prng
);
471 in_csum
= in_cksum(buffer
, exercise
);
472 in_csum_res
= in_cksum_optimized(buffer
, exercise
);
473 in_csum_rfc
= in_cksum_rfc(buffer
, exercise
);
474 if (in_csum_res
!= in_csum
|| in_csum
!= in_csum_rfc
)
475 printf("\nverify: in_chksum failed in_csum:%x, in_csum_res:%x,in_csum_rfc %x, len:%d\n",
476 in_csum
, in_csum_res
, in_csum_rfc
, exercise
);
479 uint16_t in_csum_iov
;
481 iov
[0].iov_base
= buffer
;
482 iov
[0].iov_len
= exercise
/ 2;
483 iov
[1].iov_base
= buffer
+ iov
[0].iov_len
;
484 iov
[1].iov_len
= exercise
- iov
[0].iov_len
;
486 in_csum_iov
= in_cksumv(iov
, 2);
487 if (in_csum_iov
!= in_csum
)
488 printf("\nverify: in_cksumv failed, lens: %zu+%zu\n",
489 iov
[0].iov_len
, iov
[1].iov_len
);
492 /* force split with byte leftover */
493 iov
[0].iov_base
= buffer
;
494 iov
[0].iov_len
= (exercise
/ 2) | 1;
495 iov
[1].iov_base
= buffer
+ iov
[0].iov_len
;
497 iov
[2].iov_base
= buffer
+ iov
[0].iov_len
+ 2;
498 iov
[2].iov_len
= exercise
- iov
[0].iov_len
- 2;
500 in_csum_iov
= in_cksumv(iov
, 3);
501 if (in_csum_iov
!= in_csum
)
502 printf("\nverify: in_cksumv failed, lens: %zu+%zu+%zu, got %04x, expected %04x\n",
503 iov
[0].iov_len
, iov
[1].iov_len
,
504 iov
[2].iov_len
, in_csum_iov
, in_csum
);
506 /* force split without byte leftover */
507 iov
[0].iov_base
= buffer
;
508 iov
[0].iov_len
= (exercise
/ 2) & ~1UL;
509 iov
[1].iov_base
= buffer
+ iov
[0].iov_len
;
511 iov
[2].iov_base
= buffer
+ iov
[0].iov_len
+ 2;
512 iov
[2].iov_len
= exercise
- iov
[0].iov_len
- 2;
514 in_csum_iov
= in_cksumv(iov
, 3);
515 if (in_csum_iov
!= in_csum
)
516 printf("\nverify: in_cksumv failed, lens: %zu+%zu+%zu, got %04x, expected %04x\n",
517 iov
[0].iov_len
, iov
[1].iov_len
,
518 iov
[2].iov_len
, in_csum_iov
, in_csum
);
521 if (exercise
>= FLETCHER_CHECKSUM_VALIDATE
)
524 ospfd
= ospfd_checksum(buffer
, exercise
+ sizeof(uint16_t),
526 if (verify(buffer
, exercise
+ sizeof(uint16_t)))
527 printf("\nverify: ospfd failed\n");
528 isisd
= iso_csum_create(buffer
, exercise
+ sizeof(uint16_t),
530 if (verify(buffer
, exercise
+ sizeof(uint16_t)))
531 printf("\nverify: isisd failed\n");
532 lib
= fletcher_checksum(buffer
, exercise
+ sizeof(uint16_t),
534 if (verify(buffer
, exercise
+ sizeof(uint16_t)))
535 printf("\nverify: lib failed\n");
538 printf("\nMismatch in values at size %d\n"
539 "ospfd: 0x%04x\tc0: %d\tc1: %d\tx: %d\ty: %d\n"
540 "isisd: 0x%04x\tc0: %d\tc1: %d\tx: %d\ty: %d\n"
542 exercise
, ospfd
, ospfd_vals
.a
.c0
,
543 ospfd_vals
.a
.c1
, ospfd_vals
.x
, ospfd_vals
.y
,
544 isisd
, isisd_vals
.a
.c0
, isisd_vals
.a
.c1
,
545 isisd_vals
.x
, isisd_vals
.y
, lib
);
547 /* Investigate reduction phase discrepencies */
548 if (ospfd_vals
.a
.c0
== isisd_vals
.a
.c0
549 && ospfd_vals
.a
.c1
== isisd_vals
.a
.c1
) {
551 for (i
= 0; reducts
[i
].name
!= NULL
; i
++) {
552 ospfd
= reducts
[i
].f(
554 exercise
+ sizeof(uint16_t),
556 printf("%20s: x: %02x, y %02x, checksum 0x%04x\n",
559 ospfd_vals
.y
& 0xff, ospfd
);
563 printf("\n uint8_t testdata [] = {\n ");
564 for (i
= 0; i
< exercise
; i
++) {
565 printf("0x%02x,%s", buffer
[i
],
566 (i
+ 1) % 8 ? " " : "\n ");