checksum.c revision 190203
1190203Srpaulo/*
2190203Srpaulo * Copyright (c) 1998-2006 The TCPDUMP project
3190203Srpaulo *
4190203Srpaulo * Redistribution and use in source and binary forms, with or without
5190203Srpaulo * modification, are permitted provided that: (1) source code
6190203Srpaulo * distributions retain the above copyright notice and this paragraph
7190203Srpaulo * in its entirety, and (2) distributions including binary code include
8190203Srpaulo * the above copyright notice and this paragraph in its entirety in
9190203Srpaulo * the documentation or other materials provided with the distribution.
10190203Srpaulo * THIS SOFTWARE IS PROVIDED ``AS IS'' AND
11190203Srpaulo * WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT
12190203Srpaulo * LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
13190203Srpaulo * FOR A PARTICULAR PURPOSE.
14190203Srpaulo *
15190203Srpaulo * miscellaneous checksumming routines
16190203Srpaulo *
17190203Srpaulo * Original code by Hannes Gredler (hannes@juniper.net)
18190203Srpaulo */
19190203Srpaulo
20190203Srpaulo#ifndef lint
21190203Srpaulostatic const char rcsid[] _U_ =
22190203Srpaulo    "@(#) $Header: /tcpdump/master/tcpdump/checksum.c,v 1.4 2006-09-25 09:23:32 hannes Exp $";
23190203Srpaulo#endif
24190203Srpaulo
25190203Srpaulo#ifdef HAVE_CONFIG_H
26190203Srpaulo#include "config.h"
27190203Srpaulo#endif
28190203Srpaulo
29190203Srpaulo#include <tcpdump-stdinc.h>
30190203Srpaulo
31190203Srpaulo#include <stdio.h>
32190203Srpaulo#include <stdlib.h>
33190203Srpaulo#include <string.h>
34190203Srpaulo
35190203Srpaulo#include "interface.h"
36190203Srpaulo
37190203Srpaulo#define CRC10_POLYNOMIAL 0x633
38190203Srpaulostatic u_int16_t crc10_table[256];
39190203Srpaulo
40190203Srpaulostatic void
41190203Srpauloinit_crc10_table(void)
42190203Srpaulo{
43190203Srpaulo    register int i, j;
44190203Srpaulo    register u_int16_t accum;
45190203Srpaulo
46190203Srpaulo    for ( i = 0;  i < 256;  i++ )
47190203Srpaulo    {
48190203Srpaulo        accum = ((unsigned short) i << 2);
49190203Srpaulo        for ( j = 0;  j < 8;  j++ )
50190203Srpaulo        {
51190203Srpaulo            if ((accum <<= 1) & 0x400) accum ^= CRC10_POLYNOMIAL;
52190203Srpaulo        }
53190203Srpaulo        crc10_table[i] = accum;
54190203Srpaulo    }
55190203Srpaulo    return;
56190203Srpaulo}
57190203Srpaulo
58190203Srpaulou_int16_t
59190203Srpauloverify_crc10_cksum(u_int16_t accum, const u_char *p, int length)
60190203Srpaulo{
61190203Srpaulo    register int i;
62190203Srpaulo
63190203Srpaulo    for ( i = 0;  i < length;  i++ )
64190203Srpaulo    {
65190203Srpaulo        accum = ((accum << 8) & 0x3ff)
66190203Srpaulo            ^ crc10_table[( accum >> 2) & 0xff]
67190203Srpaulo            ^ *p++;
68190203Srpaulo    }
69190203Srpaulo    return accum;
70190203Srpaulo}
71190203Srpaulo
72190203Srpaulo/* precompute checksum tables */
73190203Srpaulovoid
74190203Srpauloinit_checksum(void) {
75190203Srpaulo
76190203Srpaulo    init_crc10_table();
77190203Srpaulo
78190203Srpaulo}
79190203Srpaulo
80190203Srpaulo/*
81190203Srpaulo * Creates the OSI Fletcher checksum. See 8473-1, Appendix C, section C.3.
82190203Srpaulo * The checksum field of the passed PDU does not need to be reset to zero.
83190203Srpaulo */
84190203Srpaulou_int16_t
85190203Srpaulocreate_osi_cksum (const u_int8_t *pptr, int checksum_offset, int length)
86190203Srpaulo{
87190203Srpaulo
88190203Srpaulo    int x;
89190203Srpaulo    int y;
90190203Srpaulo    u_int32_t mul;
91190203Srpaulo    u_int32_t c0;
92190203Srpaulo    u_int32_t c1;
93190203Srpaulo    u_int16_t checksum;
94190203Srpaulo    int index;
95190203Srpaulo
96190203Srpaulo    checksum = 0;
97190203Srpaulo
98190203Srpaulo    c0 = 0;
99190203Srpaulo    c1 = 0;
100190203Srpaulo
101190203Srpaulo    for (index = 0; index < length; index++) {
102190203Srpaulo        /*
103190203Srpaulo         * Ignore the contents of the checksum field.
104190203Srpaulo         */
105190203Srpaulo        if (index == checksum_offset ||
106190203Srpaulo            index == checksum_offset+1) {
107190203Srpaulo            c1 += c0;
108190203Srpaulo            pptr++;
109190203Srpaulo        } else {
110190203Srpaulo            c0 = c0 + *(pptr++);
111190203Srpaulo            c1 += c0;
112190203Srpaulo        }
113190203Srpaulo    }
114190203Srpaulo
115190203Srpaulo    c0 = c0 % 255;
116190203Srpaulo    c1 = c1 % 255;
117190203Srpaulo
118190203Srpaulo    mul = (length - checksum_offset)*(c0);
119190203Srpaulo
120190203Srpaulo    x = mul - c0 - c1;
121190203Srpaulo    y = c1 - mul - 1;
122190203Srpaulo
123190203Srpaulo    if ( y >= 0 ) y++;
124190203Srpaulo    if ( x < 0 ) x--;
125190203Srpaulo
126190203Srpaulo    x %= 255;
127190203Srpaulo    y %= 255;
128190203Srpaulo
129190203Srpaulo
130190203Srpaulo    if (x == 0) x = 255;
131190203Srpaulo    if (y == 0) y = 255;
132190203Srpaulo
133190203Srpaulo    y &= 0x00FF;
134190203Srpaulo    checksum = ((x << 8) | y);
135190203Srpaulo
136190203Srpaulo    return checksum;
137190203Srpaulo}
138