summaryrefslogtreecommitdiffstats
path: root/ax25ipd/crc.c
blob: c6d8eea36c4cc4967bdbf10fadcf753bd676d65d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
/* crc.c 		Computations involving CRCs */

#include "ax25ipd.h"
/*
 **********************************************************************
 * The following code was taken from Appendix B of RFC 1171
 * (Point-to-Point Protocol)
 *
 * The RFC credits the following sources for this implementation:
 *
 *   Perez, "Byte-wise CRC Calculations", IEEE Micro, June, 1983.
 *
 *   Morse, G., "Calculating CRC's by Bits and Bytes", Byte,
 *   September 1986.
 *
 *   LeVan, J., "A Fast CRC", Byte, November 1987.
 *
 *
 * The HDLC polynomial: x**0 + x**5 + x**12 + x**16
 */

/*
 * u16 represents an unsigned 16-bit number.  Adjust the typedef for
 * your hardware.
 */
typedef unsigned short u16;


/*
 * FCS lookup table as calculated by the table generator in section 2.
 */
static u16 fcstab[256] = {
	0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf,
	0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7,
	0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e,
	0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876,
	0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd,
	0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5,
	0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c,
	0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974,
	0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb,
	0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3,
	0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a,
	0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72,
	0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9,
	0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1,
	0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738,
	0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70,
	0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7,
	0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff,
	0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036,
	0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e,
	0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5,
	0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd,
	0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134,
	0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c,
	0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3,
	0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb,
	0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232,
	0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a,
	0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1,
	0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9,
	0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330,
	0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78
};

#define PPPINITFCS      0xffff	/* Initial FCS value */
#define PPPGOODFCS      0xf0b8	/* Good final FCS value */

/*
 * Calculate a new fcs given the current fcs and the new data.
 */
u16 pppfcs(u16 fcs, unsigned char *cp, int len)
{
/*    ASSERT(sizeof (u16) == 2); */
/*    ASSERT(((u16) -1) > 0);    */
	while (len--)
		fcs = (fcs >> 8) ^ fcstab[(fcs ^ *cp++) & 0xff];

	return fcs;
}

/*
 * End code from Appendix B of RFC 1171
 **********************************************************************
 */

/*
 *  The following routines are simply convenience routines...
 *  I'll merge them into the mainline code when suitably debugged
 */

/* Return the computed CRC */
unsigned short int compute_crc(unsigned char *buf, int l)
{
	int fcs;

	fcs = PPPINITFCS;
	fcs = pppfcs(fcs, buf, l);
	fcs ^= 0xffff;
	return fcs;
}

/* Return true if the CRC is correct */
int ok_crc(unsigned char *buf, int l)
{
	int fcs;

	fcs = PPPINITFCS;
	fcs = pppfcs(fcs, buf, l);
	return fcs == PPPGOODFCS;
}

/*
 * A test routine to make sure the CRC is working right on your hardware.
 * cc -DTEST crc.c
 *
 */

#ifdef TEST
void main(int argc, char *argv[])
{
	unsigned char buf[258];
	int l, i;
	unsigned short int f;

	l = 256;
	for (i = 0; i < l; i++) {
		buf[i] = i;
	}

	f = compute_crc(buf, l);
	printf("computed crc=0x%04x\n", f);

	buf[l] = (f & 0xff);
	buf[l + 1] = (f >> 8);
	printf("crc should be good... ");
	i = ok_crc(buf, l + 2);
	if (i)
		printf("CRC declared OK\n");
	else
		printf("CRC declared bad\n");

	buf[l + 1] = (f & 0xff);
	buf[l] = (f >> 8);
	printf("reversed the CRC byte order... CRC should be bad...");
	i = ok_crc(buf, l + 2);
	if (i)
		printf("CRC declared OK\n");
	else
		printf("CRC declared bad\n");

	printf("changed the frame length... CRC should be bad...");
	i = ok_crc(buf, l + 1);
	if (i)
		printf("CRC declared OK\n");
	else
		printf("CRC declared bad\n");

	buf[0] -= 1;
	printf("corrupted the data... CRC should be bad...");
	i = ok_crc(buf, l + 2);
	if (i)
		printf("CRC declared OK\n");
	else
		printf("CRC declared bad\n");

}
#endif