blob: a5724943aa2e9511cbdfc5ca6abf0b0ebe4274fc [file] [log] [blame]
/*
* 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) && (strcmp(argv[1], debugoption) == 0)) {
#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;
}