Bruce Griffith | 3a2310e | 2014-07-16 11:25:21 -0600 | [diff] [blame] | 1 | /* |
| 2 | * Copyright (c) 1998-2006 The TCPDUMP project |
| 3 | * 2014 Sage Electronic Engineering, LLC |
| 4 | * All Rights Reserved |
| 5 | * |
| 6 | * Redistribution and use in source and binary forms, with or without |
| 7 | * modification, are permitted provided that: (1) source code |
| 8 | * distributions retain the above copyright notice and this paragraph |
| 9 | * in its entirety, and (2) distributions including binary code include |
| 10 | * the above copyright notice and this paragraph in its entirety in |
| 11 | * the documentation or other materials provided with the distribution. |
| 12 | * THIS SOFTWARE IS PROVIDED ``AS IS'' AND |
| 13 | * WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT |
| 14 | * LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS |
| 15 | * FOR A PARTICULAR PURPOSE. |
| 16 | * |
| 17 | * Original code by Hannes Gredler <hannes@juniper.net> |
| 18 | * Rewritten for Fletcher32 by Bruce Griffith <Bruce.Griffith@se-eng.com> |
| 19 | */ |
| 20 | |
| 21 | #include <errno.h> |
| 22 | #include <stdio.h> |
| 23 | #include <sys/stat.h> |
| 24 | #include <sys/types.h> |
| 25 | #include <unistd.h> |
| 26 | #include <string.h> |
| 27 | |
| 28 | #define MAX_PSP_DIRECTORY_SIZE 512 |
| 29 | |
| 30 | typedef unsigned int uint32_t; |
| 31 | typedef unsigned char uint8_t; |
| 32 | typedef unsigned short uint16_t; |
| 33 | |
| 34 | /* |
| 35 | * Creates the OSI Fletcher checksum. See 8473-1, Appendix C, section C.3. |
| 36 | * The checksum field of the passed PDU does not need to be reset to zero. |
| 37 | * |
| 38 | * The "Fletcher Checksum" was proposed in a paper by John G. Fletcher of |
| 39 | * Lawrence Livermore Labs. The Fletcher Checksum was proposed as an |
| 40 | * alternative to cyclical redundancy checks because it provides error- |
| 41 | * detection properties similar to cyclical redundancy checks but at the |
| 42 | * cost of a simple summation technique. Its characteristics were first |
| 43 | * published in IEEE Transactions on Communications in January 1982. One |
| 44 | * version has been adopted by ISO for use in the class-4 transport layer |
| 45 | * of the network protocol. |
| 46 | * |
| 47 | * This program expects: |
| 48 | * stdin: The input file to compute a checksum for. The input file |
| 49 | * not be longer than 256 bytes. |
| 50 | * stdout: Copied from the input file with the Fletcher's Checksum |
| 51 | * inserted 8 bytes after the beginning of the file. |
| 52 | * stderr: Used to print out error messages. |
| 53 | */ |
| 54 | |
| 55 | uint32_t fletcher32 (const uint16_t *pptr, int length) |
| 56 | { |
| 57 | |
| 58 | uint32_t c0; |
| 59 | uint32_t c1; |
| 60 | uint32_t checksum; |
| 61 | int index; |
| 62 | |
| 63 | c0 = 0xFFFF; |
| 64 | c1 = 0xFFFF; |
| 65 | |
| 66 | for (index = 0; index < length; index++) { |
| 67 | /* |
| 68 | * Ignore the contents of the checksum field. |
| 69 | */ |
| 70 | c0 += *(pptr++); |
| 71 | c1 += c0; |
| 72 | if ((index % 360) == 0) { |
| 73 | c0 = (c0 & 0xFFFF) + (c0 >> 16); // Sum0 modulo 65535 + the overflow |
| 74 | c1 = (c1 & 0xFFFF) + (c1 >> 16); // Sum1 modulo 65535 + the overflow |
| 75 | } |
| 76 | |
| 77 | } |
| 78 | |
| 79 | c0 = (c0 & 0xFFFF) + (c0 >> 16); // Sum0 modulo 65535 + the overflow |
| 80 | c1 = (c1 & 0xFFFF) + (c1 >> 16); // Sum1 modulo 65535 + the overflow |
| 81 | checksum = (c1 << 16) | c0; |
| 82 | |
| 83 | return checksum; |
| 84 | } |
| 85 | |
| 86 | int main(int argc, char **argv) |
| 87 | { |
| 88 | uint32_t checksum = 0xFFFFFFFF; |
| 89 | struct stat filestat = {}; |
| 90 | int retcode = EINVAL; |
| 91 | size_t filesize = 0; |
| 92 | char debugoption[] = "--print"; |
| 93 | |
| 94 | uint16_t buffer[MAX_PSP_DIRECTORY_SIZE / sizeof(uint16_t)]; |
| 95 | |
| 96 | retcode = fstat(fileno(stdin), &filestat); |
| 97 | filesize = filestat.st_size; |
| 98 | if (retcode < 0) { |
| 99 | perror("FLETCHER32"); |
| 100 | return errno; |
| 101 | } else if (!((12 < filesize) && (filesize <= sizeof(buffer)))) { |
| 102 | fprintf(stderr, "FLETCHER32: input file is not valid for this program.\n"); |
| 103 | return EINVAL; |
| 104 | } |
| 105 | retcode = read(fileno(stdin), (void *)buffer, filesize); |
| 106 | if (retcode < 0) { |
| 107 | perror("FLETCHER32"); |
| 108 | return errno; |
| 109 | } |
| 110 | |
| 111 | checksum = fletcher32(&buffer[2], filesize/2 - 2); |
| 112 | *((uint32_t *)& buffer[2]) = checksum; |
| 113 | #ifndef DEBUG |
Patrick Georgi | 667c7a3 | 2014-09-29 10:12:29 +0200 | [diff] [blame] | 114 | if ((argc == 2) && (strcmp(argv[1], debugoption) == 0)) { |
Bruce Griffith | 3a2310e | 2014-07-16 11:25:21 -0600 | [diff] [blame] | 115 | #endif |
| 116 | fprintf(stderr, "Fletcher's Checksum: %x\n", checksum); |
| 117 | #ifndef DEBUG |
| 118 | } |
| 119 | #endif |
| 120 | |
| 121 | retcode = write(fileno(stdout), buffer, filesize); |
| 122 | if (retcode < 0) { |
| 123 | perror("FLETCHER32"); |
| 124 | return errno; |
| 125 | } |
| 126 | |
| 127 | return 0; |
| 128 | } |