/*************************************************************************
* (C) 2008 AITNET ltd - Sofia/Bulgaria - <misho@aitbg.com>
* by Michael Pounov <misho@openbsd-bg.org>
*
* $Author: misho $
* $Id: aitcrc.c,v 1.1.1.1.2.2 2010/01/20 00:10:01 misho Exp $
*
*************************************************************************/
#include "global.h"
static int crc_Errno;
static char crc_Error[MAX_STR + 1];
// Adler module
const u_long crc_modAdler = 0xFFF1L;
// All known library CRC types ...
const crcPoly_t crc_Poly[] = {
{ 1, (u_long) 0x1, "CRC-1-Parity" },
{ 4, (u_long) 0x3, "CRC-4-ITU" },
{ 5, (u_long) 0x15, "CRC-5-ITU" },
{ 6, (u_long) 0x3, "CRC-6-ITU" },
{ 7, (u_long) 0x9, "CRC-7-MMC" },
{ 8, (u_long) 0x8D, "CRC-8-CCITT" },
{ 10, (u_long) 0x233, "CRC-10" },
{ 11, (u_long) 0x385, "CRC-11-FlexRay" },
{ 12, (u_long) 0x80F, "CRC-12-Telco" },
{ 15, (u_long) 0x4599, "CRC-15-CAN" },
{ 16, (u_long) 0x8005, "CRC-16-IBM" },
{ 24, (u_long) 0x864CFB, "CRC-24-Radix64" },
{ 30, (u_long) 0x2030B9C7, "CRC-30-CDMA" },
{ 32, (u_long) 0x04C11DB7, "CRC-32-802.3" }
};
// ----------------------------------------------------------
//
// Error maintenance functions ...
//
// crc_GetErrno() Get error code of last operation
inline int crc_GetErrno()
{
return crc_Errno;
}
// crc_GetError() Get error text of last operation
inline const char *crc_GetError()
{
return crc_Error;
}
// crcSetErr() Set error to variables for internal use!!!
inline void crcSetErr(int eno, char *estr, ...)
{
va_list lst;
crc_Errno = eno;
memset(crc_Error, 0, MAX_STR + 1);
va_start(lst, estr);
vsnprintf(crc_Error, MAX_STR + 1, estr, lst);
va_end(lst);
}
// ----------------------------------------------------------
/*
* crcReflect() Reflect all bits of number
* @crcNum = Number for reflection
* @crcBits = Number width bits
* return: -1 error, !=-1 reflecting number
*/
inline u_long crcReflect(u_long crcNum, u_char crcBits)
{
register u_long i, j, rev;
for (i = (u_long) 1 << (crcBits - 1), j = 1, rev ^= rev; i; i >>= 1, j <<= 1)
if (crcNum & i)
rev |= j;
crc_Errno ^= crc_Errno;
return rev;
}
/*
* crcCalc() Generic CRC calculation function for many sub variants of CRC algorithms
* @psBuf = Data for calculation
* @bufLen = Length of data
* @crcBits = CRC algorithm bits (1, 4, 5, 6, 7, 8, 10, 11, 12, 15, 16, 24, 30, 32)
* @RevOpts = Options for computation (REVOPTS_REVERTBYTE, REVOPTS_REVERTCRC)
* @initCRC = Initial CRC value
* @xorCRC = Last xor CRC value
* return: -1 error, !=-1 CRC checksum
*/
inline u_long crcCalc(u_char * __restrict psBuf, u_int bufLen, u_char crcBits, u_char RevOpts, u_long initCRC, u_long xorCRC)
{
const u_long bits = sizeof(long) * 8 - crcBits;
u_long poly, crchibit, crc;
register u_long i, j, b, ch;
if (!psBuf) {
crc_Errno = 1;
strlcpy(crc_Error, "crcCalc(): Invalid parameters!", MAX_STR + 1);
return -1;
}
switch (crcBits) {
case 1:
poly = crc_Poly[0].poly_num;
break;
case 4:
poly = crc_Poly[1].poly_num;
break;
case 5:
poly = crc_Poly[2].poly_num;
break;
case 6:
poly = crc_Poly[3].poly_num;
break;
case 7:
poly = crc_Poly[4].poly_num;
break;
case 8:
poly = crc_Poly[5].poly_num;
break;
case 10:
poly = crc_Poly[6].poly_num;
break;
case 11:
poly = crc_Poly[7].poly_num;
break;
case 12:
poly = crc_Poly[8].poly_num;
break;
case 15:
poly = crc_Poly[9].poly_num;
break;
case 16:
poly = crc_Poly[10].poly_num;
break;
case 24:
poly = crc_Poly[11].poly_num;
break;
case 30:
poly = crc_Poly[12].poly_num;
break;
case 32:
poly = crc_Poly[13].poly_num;
break;
default:
crc_Errno = 2;
strlcpy(crc_Error, "crcCalc(): Unsupported CRC method!!!", MAX_STR + 1);
return -1;
}
poly <<= bits;
crchibit = (u_long) 1 << (crcBits - 1);
crchibit <<= bits;
crc = initCRC << bits;
for (i = 0; i < bufLen; i++) {
ch = (u_long) *psBuf++;
if (RevOpts & REVOPTS_REVERTBYTE)
ch = crcReflect(ch, 8);
for (j = 0x80; j; j >>= 1) {
b = crc & crchibit;
crc <<= 1;
if (ch & j)
b ^= crchibit;
if (b)
crc ^= poly;
}
}
if (RevOpts & REVOPTS_REVERTCRC)
crc = crcReflect(crc, sizeof(long) * 8);
crc ^= xorCRC << bits;
crc &= (((crchibit - 1) << 1) | 1);
if (!(RevOpts & REVOPTS_REVERTCRC))
crc >>= bits;
crc_Errno ^= crc_Errno;
return crc;
}
// ----------------------------------------------------------
/*
* crcIP() Checksum in IP communication
* @nBuf = Data for calculation
* @bufLen = Length of data
* return: -1 error, !=-1 Checksum
*/
inline u_short crcIP(u_short * __restrict nBuf, int bufLen)
{
register u_long sum;
if (!nBuf) {
crc_Errno = 1;
strlcpy(crc_Error, "crcIP(): Invalid parameters!", MAX_STR + 1);
return -1;
}
for (sum = 0; bufLen; bufLen--)
sum += *nBuf++;
sum = (sum >> 16) + (sum & 0xFFFF);
sum += sum >> 16;
crc_Errno ^= crc_Errno;
return (u_short) ~sum;
}
/*
* crcFletcher() Fletcher-16 Checksum computing
* @nBuf = Data for calculation
* @bufLen = Length of data
* return: -1 error, !=-1 Checksum
*/
inline u_long crcFletcher(u_short * __restrict nBuf, int bufLen)
{
register u_long s1, s2, clen;
if (!nBuf) {
crc_Errno = 1;
strlcpy(crc_Error, "crcFletcher(): Invalid parameters!", MAX_STR + 1);
return -1;
}
s1 = s2 = 0xFFFF;
while (bufLen) {
clen = bufLen > MAX_FLETCHER_DIGEST ? MAX_FLETCHER_DIGEST : bufLen;
bufLen -= clen;
do {
s1 += (u_long) *nBuf++;
s2 += s1;
} while (--clen);
s1 = (s1 >> 16) + (s1 & 0xFFFF);
s2 = (s2 >> 16) + (s2 & 0xFFFF);
}
crc_Errno ^= crc_Errno;
return (s2 << 16) | s1;
}
/*
* crcAdler() crcAdler-32 Checksum computing
* @psBuf = Data for calculation
* @bufLen = Length of data
* return: -1 error, !=-1 Checksum
*/
inline u_long crcAdler(u_char * __restrict psBuf, int bufLen)
{
register u_long s1, s2, clen;
if (!psBuf) {
crc_Errno = 1;
strlcpy(crc_Error, "crcAdler(): Invalid parameters!", MAX_STR + 1);
return -1;
}
s1 = 1L;
s2 ^= s2;
while (bufLen) {
clen = bufLen > MAX_ADLER_DIGEST ? MAX_ADLER_DIGEST : bufLen;
bufLen -= clen;
do {
s1 += (u_long) *psBuf++;
s2 += s1;
} while (--clen);
s1 %= crc_modAdler;
s2 %= crc_modAdler;
}
crc_Errno ^= crc_Errno;
return (s2 << 16) | s1;
}
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>