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