Home | History | Annotate | Line # | Download | only in dist
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