| /* |
| * Copyright (c) 1998-2006 The TCPDUMP project |
| * 2014 Sage Electronic Engineering, LLC |
| * All Rights Reserved |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that: (1) source code |
| * distributions retain the above copyright notice and this paragraph |
| * in its entirety, and (2) distributions including binary code include |
| * the above copyright notice and this paragraph in its entirety in |
| * the documentation or other materials provided with the distribution. |
| * THIS SOFTWARE IS PROVIDED ``AS IS'' AND |
| * WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT |
| * LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS |
| * FOR A PARTICULAR PURPOSE. |
| * |
| * Original code by Hannes Gredler <hannes@juniper.net> |
| * Rewritten for Fletcher32 by Bruce Griffith <Bruce.Griffith@se-eng.com> |
| */ |
| |
| #include <errno.h> |
| #include <stdio.h> |
| #include <sys/stat.h> |
| #include <sys/types.h> |
| #include <unistd.h> |
| #include <string.h> |
| |
| #define MAX_PSP_DIRECTORY_SIZE 512 |
| |
| typedef unsigned int uint32_t; |
| typedef unsigned char uint8_t; |
| typedef unsigned short uint16_t; |
| |
| /* |
| * Creates the OSI Fletcher checksum. See 8473-1, Appendix C, section C.3. |
| * The checksum field of the passed PDU does not need to be reset to zero. |
| * |
| * The "Fletcher Checksum" was proposed in a paper by John G. Fletcher of |
| * Lawrence Livermore Labs. The Fletcher Checksum was proposed as an |
| * alternative to cyclical redundancy checks because it provides error- |
| * detection properties similar to cyclical redundancy checks but at the |
| * cost of a simple summation technique. Its characteristics were first |
| * published in IEEE Transactions on Communications in January 1982. One |
| * version has been adopted by ISO for use in the class-4 transport layer |
| * of the network protocol. |
| * |
| * This program expects: |
| * stdin: The input file to compute a checksum for. The input file |
| * not be longer than 256 bytes. |
| * stdout: Copied from the input file with the Fletcher's Checksum |
| * inserted 8 bytes after the beginning of the file. |
| * stderr: Used to print out error messages. |
| */ |
| |
| uint32_t fletcher32 (const uint16_t *pptr, int length) |
| { |
| |
| uint32_t c0; |
| uint32_t c1; |
| uint32_t checksum; |
| int index; |
| |
| c0 = 0xFFFF; |
| c1 = 0xFFFF; |
| |
| for (index = 0; index < length; index++) { |
| /* |
| * Ignore the contents of the checksum field. |
| */ |
| c0 += *(pptr++); |
| c1 += c0; |
| if ((index % 360) == 0) { |
| c0 = (c0 & 0xFFFF) + (c0 >> 16); // Sum0 modulo 65535 + the overflow |
| c1 = (c1 & 0xFFFF) + (c1 >> 16); // Sum1 modulo 65535 + the overflow |
| } |
| |
| } |
| |
| c0 = (c0 & 0xFFFF) + (c0 >> 16); // Sum0 modulo 65535 + the overflow |
| c1 = (c1 & 0xFFFF) + (c1 >> 16); // Sum1 modulo 65535 + the overflow |
| checksum = (c1 << 16) | c0; |
| |
| return checksum; |
| } |
| |
| int main(int argc, char **argv) |
| { |
| uint32_t checksum = 0xFFFFFFFF; |
| struct stat filestat = {}; |
| int retcode = EINVAL; |
| size_t filesize = 0; |
| char debugoption[] = "--print"; |
| |
| uint16_t buffer[MAX_PSP_DIRECTORY_SIZE / sizeof(uint16_t)]; |
| |
| retcode = fstat(fileno(stdin), &filestat); |
| filesize = filestat.st_size; |
| if (retcode < 0) { |
| perror("FLETCHER32"); |
| return errno; |
| } else if (!((12 < filesize) && (filesize <= sizeof(buffer)))) { |
| fprintf(stderr, "FLETCHER32: input file is not valid for this program.\n"); |
| return EINVAL; |
| } |
| retcode = read(fileno(stdin), (void *)buffer, filesize); |
| if (retcode < 0) { |
| perror("FLETCHER32"); |
| return errno; |
| } |
| |
| checksum = fletcher32(&buffer[2], filesize/2 - 2); |
| *((uint32_t *)& buffer[2]) = checksum; |
| #ifndef DEBUG |
| if ((argc == 2) && !strncmp(argv[1], debugoption, sizeof(debugoption+1))) { |
| #endif |
| fprintf(stderr, "Fletcher's Checksum: %x\n", checksum); |
| #ifndef DEBUG |
| } |
| #endif |
| |
| retcode = write(fileno(stdout), buffer, filesize); |
| if (retcode < 0) { |
| perror("FLETCHER32"); |
| return errno; |
| } |
| |
| return 0; |
| } |