checksum.c revision 1.6 1 1.1 christos /*
2 1.1 christos * Copyright (c) 1998-2006 The TCPDUMP project
3 1.1 christos *
4 1.1 christos * Redistribution and use in source and binary forms, with or without
5 1.1 christos * modification, are permitted provided that: (1) source code
6 1.1 christos * distributions retain the above copyright notice and this paragraph
7 1.1 christos * in its entirety, and (2) distributions including binary code include
8 1.1 christos * the above copyright notice and this paragraph in its entirety in
9 1.1 christos * the documentation or other materials provided with the distribution.
10 1.1 christos * THIS SOFTWARE IS PROVIDED ``AS IS'' AND
11 1.1 christos * WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT
12 1.1 christos * LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
13 1.1 christos * FOR A PARTICULAR PURPOSE.
14 1.1 christos *
15 1.1 christos * miscellaneous checksumming routines
16 1.1 christos *
17 1.1 christos * Original code by Hannes Gredler (hannes (at) juniper.net)
18 1.1 christos */
19 1.1 christos
20 1.2 christos #include <sys/cdefs.h>
21 1.1 christos #ifndef lint
22 1.6 christos __RCSID("$NetBSD: checksum.c,v 1.6 2017/01/24 23:29:13 christos Exp $");
23 1.1 christos #endif
24 1.1 christos
25 1.1 christos #ifdef HAVE_CONFIG_H
26 1.1 christos #include "config.h"
27 1.1 christos #endif
28 1.1 christos
29 1.6 christos #include <netdissect-stdinc.h>
30 1.1 christos
31 1.1 christos #include <stdio.h>
32 1.1 christos #include <stdlib.h>
33 1.1 christos #include <string.h>
34 1.1 christos #include <assert.h>
35 1.1 christos
36 1.6 christos #include "netdissect.h"
37 1.1 christos
38 1.1 christos /*
39 1.1 christos * CRC-10 table generated using the following Python snippet:
40 1.1 christos
41 1.1 christos import sys
42 1.1 christos
43 1.1 christos crc_table = []
44 1.1 christos for i in range(256):
45 1.1 christos accum = i << 2
46 1.1 christos for j in range(8):
47 1.1 christos accum <<= 1
48 1.1 christos if accum & 0x400:
49 1.1 christos accum ^= 0x633
50 1.1 christos crc_table.append(accum)
51 1.1 christos
52 1.1 christos for i in range(len(crc_table)/8):
53 1.1 christos for j in range(8):
54 1.1 christos sys.stdout.write("0x%04x, " % crc_table[i*8+j])
55 1.1 christos sys.stdout.write("\n")
56 1.1 christos
57 1.1 christos */
58 1.5 christos static const uint16_t crc10_table[256] =
59 1.1 christos {
60 1.1 christos 0x0000, 0x0233, 0x0255, 0x0066, 0x0299, 0x00aa, 0x00cc, 0x02ff,
61 1.1 christos 0x0301, 0x0132, 0x0154, 0x0367, 0x0198, 0x03ab, 0x03cd, 0x01fe,
62 1.1 christos 0x0031, 0x0202, 0x0264, 0x0057, 0x02a8, 0x009b, 0x00fd, 0x02ce,
63 1.1 christos 0x0330, 0x0103, 0x0165, 0x0356, 0x01a9, 0x039a, 0x03fc, 0x01cf,
64 1.1 christos 0x0062, 0x0251, 0x0237, 0x0004, 0x02fb, 0x00c8, 0x00ae, 0x029d,
65 1.1 christos 0x0363, 0x0150, 0x0136, 0x0305, 0x01fa, 0x03c9, 0x03af, 0x019c,
66 1.1 christos 0x0053, 0x0260, 0x0206, 0x0035, 0x02ca, 0x00f9, 0x009f, 0x02ac,
67 1.1 christos 0x0352, 0x0161, 0x0107, 0x0334, 0x01cb, 0x03f8, 0x039e, 0x01ad,
68 1.1 christos 0x00c4, 0x02f7, 0x0291, 0x00a2, 0x025d, 0x006e, 0x0008, 0x023b,
69 1.1 christos 0x03c5, 0x01f6, 0x0190, 0x03a3, 0x015c, 0x036f, 0x0309, 0x013a,
70 1.1 christos 0x00f5, 0x02c6, 0x02a0, 0x0093, 0x026c, 0x005f, 0x0039, 0x020a,
71 1.1 christos 0x03f4, 0x01c7, 0x01a1, 0x0392, 0x016d, 0x035e, 0x0338, 0x010b,
72 1.1 christos 0x00a6, 0x0295, 0x02f3, 0x00c0, 0x023f, 0x000c, 0x006a, 0x0259,
73 1.1 christos 0x03a7, 0x0194, 0x01f2, 0x03c1, 0x013e, 0x030d, 0x036b, 0x0158,
74 1.1 christos 0x0097, 0x02a4, 0x02c2, 0x00f1, 0x020e, 0x003d, 0x005b, 0x0268,
75 1.1 christos 0x0396, 0x01a5, 0x01c3, 0x03f0, 0x010f, 0x033c, 0x035a, 0x0169,
76 1.1 christos 0x0188, 0x03bb, 0x03dd, 0x01ee, 0x0311, 0x0122, 0x0144, 0x0377,
77 1.1 christos 0x0289, 0x00ba, 0x00dc, 0x02ef, 0x0010, 0x0223, 0x0245, 0x0076,
78 1.1 christos 0x01b9, 0x038a, 0x03ec, 0x01df, 0x0320, 0x0113, 0x0175, 0x0346,
79 1.1 christos 0x02b8, 0x008b, 0x00ed, 0x02de, 0x0021, 0x0212, 0x0274, 0x0047,
80 1.1 christos 0x01ea, 0x03d9, 0x03bf, 0x018c, 0x0373, 0x0140, 0x0126, 0x0315,
81 1.1 christos 0x02eb, 0x00d8, 0x00be, 0x028d, 0x0072, 0x0241, 0x0227, 0x0014,
82 1.1 christos 0x01db, 0x03e8, 0x038e, 0x01bd, 0x0342, 0x0171, 0x0117, 0x0324,
83 1.1 christos 0x02da, 0x00e9, 0x008f, 0x02bc, 0x0043, 0x0270, 0x0216, 0x0025,
84 1.1 christos 0x014c, 0x037f, 0x0319, 0x012a, 0x03d5, 0x01e6, 0x0180, 0x03b3,
85 1.1 christos 0x024d, 0x007e, 0x0018, 0x022b, 0x00d4, 0x02e7, 0x0281, 0x00b2,
86 1.1 christos 0x017d, 0x034e, 0x0328, 0x011b, 0x03e4, 0x01d7, 0x01b1, 0x0382,
87 1.1 christos 0x027c, 0x004f, 0x0029, 0x021a, 0x00e5, 0x02d6, 0x02b0, 0x0083,
88 1.1 christos 0x012e, 0x031d, 0x037b, 0x0148, 0x03b7, 0x0184, 0x01e2, 0x03d1,
89 1.1 christos 0x022f, 0x001c, 0x007a, 0x0249, 0x00b6, 0x0285, 0x02e3, 0x00d0,
90 1.1 christos 0x011f, 0x032c, 0x034a, 0x0179, 0x0386, 0x01b5, 0x01d3, 0x03e0,
91 1.1 christos 0x021e, 0x002d, 0x004b, 0x0278, 0x0087, 0x02b4, 0x02d2, 0x00e1
92 1.1 christos };
93 1.1 christos
94 1.1 christos static void
95 1.1 christos init_crc10_table(void)
96 1.5 christos {
97 1.1 christos #define CRC10_POLYNOMIAL 0x633
98 1.1 christos register int i, j;
99 1.5 christos register uint16_t accum;
100 1.5 christos uint16_t verify_crc10_table[256];
101 1.5 christos
102 1.1 christos for ( i = 0; i < 256; i++ )
103 1.1 christos {
104 1.1 christos accum = ((unsigned short) i << 2);
105 1.1 christos for ( j = 0; j < 8; j++ )
106 1.1 christos {
107 1.1 christos if ((accum <<= 1) & 0x400) accum ^= CRC10_POLYNOMIAL;
108 1.1 christos }
109 1.1 christos verify_crc10_table[i] = accum;
110 1.1 christos }
111 1.1 christos assert(memcmp(verify_crc10_table,
112 1.1 christos crc10_table,
113 1.1 christos sizeof(verify_crc10_table)) == 0);
114 1.1 christos #undef CRC10_POLYNOMIAL
115 1.1 christos }
116 1.1 christos
117 1.5 christos uint16_t
118 1.5 christos verify_crc10_cksum(uint16_t accum, const u_char *p, int length)
119 1.1 christos {
120 1.1 christos register int i;
121 1.1 christos
122 1.1 christos for ( i = 0; i < length; i++ )
123 1.1 christos {
124 1.1 christos accum = ((accum << 8) & 0x3ff)
125 1.1 christos ^ crc10_table[( accum >> 2) & 0xff]
126 1.1 christos ^ *p++;
127 1.1 christos }
128 1.1 christos return accum;
129 1.1 christos }
130 1.1 christos
131 1.1 christos /* precompute checksum tables */
132 1.1 christos void
133 1.1 christos init_checksum(void) {
134 1.1 christos
135 1.1 christos init_crc10_table();
136 1.1 christos
137 1.1 christos }
138 1.1 christos
139 1.1 christos /*
140 1.1 christos * Creates the OSI Fletcher checksum. See 8473-1, Appendix C, section C.3.
141 1.1 christos * The checksum field of the passed PDU does not need to be reset to zero.
142 1.1 christos */
143 1.5 christos uint16_t
144 1.5 christos create_osi_cksum (const uint8_t *pptr, int checksum_offset, int length)
145 1.1 christos {
146 1.1 christos
147 1.1 christos int x;
148 1.1 christos int y;
149 1.5 christos uint32_t mul;
150 1.5 christos uint32_t c0;
151 1.5 christos uint32_t c1;
152 1.5 christos uint16_t checksum;
153 1.6 christos int idx;
154 1.1 christos
155 1.1 christos c0 = 0;
156 1.1 christos c1 = 0;
157 1.1 christos
158 1.6 christos for (idx = 0; idx < length; idx++) {
159 1.1 christos /*
160 1.1 christos * Ignore the contents of the checksum field.
161 1.1 christos */
162 1.6 christos if (idx == checksum_offset ||
163 1.6 christos idx == checksum_offset+1) {
164 1.1 christos c1 += c0;
165 1.1 christos pptr++;
166 1.1 christos } else {
167 1.1 christos c0 = c0 + *(pptr++);
168 1.1 christos c1 += c0;
169 1.5 christos }
170 1.1 christos }
171 1.1 christos
172 1.1 christos c0 = c0 % 255;
173 1.1 christos c1 = c1 % 255;
174 1.1 christos
175 1.1 christos mul = (length - checksum_offset)*(c0);
176 1.5 christos
177 1.1 christos x = mul - c0 - c1;
178 1.1 christos y = c1 - mul - 1;
179 1.1 christos
180 1.1 christos if ( y >= 0 ) y++;
181 1.1 christos if ( x < 0 ) x--;
182 1.1 christos
183 1.1 christos x %= 255;
184 1.1 christos y %= 255;
185 1.1 christos
186 1.1 christos
187 1.1 christos if (x == 0) x = 255;
188 1.1 christos if (y == 0) y = 255;
189 1.1 christos
190 1.1 christos y &= 0x00FF;
191 1.1 christos checksum = ((x << 8) | y);
192 1.5 christos
193 1.1 christos return checksum;
194 1.1 christos }
195