OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [trunk/] [uclinux/] [uClinux-2.0.x/] [arch/] [or32/] [lib/] [checksum.c] - Blame information for rev 1765

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 666 simons
/*
2
 * INET         An implementation of the TCP/IP protocol suite for the LINUX
3
 *              operating system.  INET is implemented using the  BSD Socket
4
 *              interface as the means of communication with the user level.
5
 *
6
 *              IP/TCP/UDP checksumming routines
7
 *
8
 * Authors:     Jorge Cwik, <jorge@laser.satlink.net>
9
 *              Arnt Gulbrandsen, <agulbra@nvg.unit.no>
10
 *              Tom May, <ftom@netcom.com>
11
 *              Andreas Schwab, <schwab@issan.informatik.uni-dortmund.de>
12
 *              Lots of code moved from tcp.c and ip.c; see those files
13
 *              for more names.
14
 *
15
 * 03/02/96     Jes Sorensen, Andreas Schwab, Roman Hodek:
16
 *              Fixed some nasty bugs, causing some horrible crashes.
17
 *              A: At some points, the sum (%0) was used as
18
 *              length-counter instead of the length counter
19
 *              (%1). Thanks to Roman Hodek for pointing this out.
20
 *              B: GCC seems to mess up if one uses too many
21
 *              data-registers to hold input values and one tries to
22
 *              specify d0 and d1 as scratch registers. Letting gcc choose these
23
 *      registers itself solves the problem.
24
 *
25
 *              This program is free software; you can redistribute it and/or
26
 *              modify it under the terms of the GNU General Public License
27
 *              as published by the Free Software Foundation; either version
28
 *              2 of the License, or (at your option) any later version.
29
 */
30
 
31
/* Revised by Kenneth Albanowski for m68knommu. Basic problem: unaligned access kills, so most
32
   of the assembly has to go. */
33
 
34
#include <net/checksum.h>
35
 
36 761 simons
extern unsigned short _ip_fast_csum(unsigned char *buf);
37
 
38 666 simons
static inline unsigned short from32to16(unsigned long x)
39
{
40
        /* add up 16-bit and 16-bit for 16+c bit */
41
        x = (x & 0xffff) + (x >> 16);
42
        /* add up carry.. */
43
        x = (x & 0xffff) + (x >> 16);
44
        return x;
45
}
46
 
47
static unsigned long do_csum(const unsigned char * buff, int len)
48
{
49
        int odd, count;
50
        unsigned long result = 0;
51
 
52
        if (len <= 0)
53
                goto out;
54
        odd = 1 & (unsigned long) buff;
55
        if (odd) {
56
                result = *buff;
57
                len--;
58
                buff++;
59
        }
60
        count = len >> 1;               /* nr of 16-bit words.. */
61
        if (count) {
62
                if (2 & (unsigned long) buff) {
63
                        result += *(unsigned short *) buff;
64
                        count--;
65
                        len -= 2;
66
                        buff += 2;
67
                }
68
                count >>= 1;            /* nr of 32-bit words.. */
69
                if (count) {
70
                        unsigned long carry = 0;
71
                        do {
72
                                unsigned long w = *(unsigned long *) buff;
73
                                count--;
74
                                buff += 4;
75
                                result += carry;
76
                                result += w;
77
                                carry = (w > result);
78
                        } while (count);
79
                        result += carry;
80
                        result = (result & 0xffff) + (result >> 16);
81
                }
82
                if (len & 2) {
83
                        result += *(unsigned short *) buff;
84
                        buff += 2;
85
                }
86
        }
87
        if (len & 1)
88
                result += (*buff << 8);
89
        result = from32to16(result);
90
        if (odd)
91
                result = ((result >> 8) & 0xff) | ((result & 0xff) << 8);
92
out:
93
        return result;
94
}
95
 
96
/*
97
 *      This is a version of ip_compute_csum() optimized for IP headers,
98
 *      which always checksum on 4 octet boundaries.
99
 */
100
unsigned short ip_fast_csum(unsigned char * iph, unsigned int ihl)
101
{
102
        return ~do_csum(iph,ihl*4);
103
}
104
 
105
/*
106
 * computes the checksum of a memory block at buff, length len,
107
 * and adds in "sum" (32-bit)
108
 *
109
 * returns a 32-bit number suitable for feeding into itself
110
 * or csum_tcpudp_magic
111
 *
112
 * this function must be called with even lengths, except
113
 * for the last fragment, which may be odd
114
 *
115
 * it's best to have buff aligned on a 32-bit boundary
116
 */
117
unsigned int csum_partial(const unsigned char * buff, int len, unsigned int sum)
118
{
119
        unsigned int result = do_csum(buff, len);
120
 
121
        /* add in old sum, and carry.. */
122
        result += sum;
123
        /* 16+c bits -> 16 bits */
124
        result = (result & 0xffff) + (result >> 16);
125
        return result;
126
}
127
 
128
/*
129
 * this routine is used for miscellaneous IP-like checksums, mainly
130
 * in icmp.c
131
 */
132
unsigned short ip_compute_csum(const unsigned char * buff, int len)
133
{
134
        return ~do_csum(buff,len);
135
}
136
 
137
/*
138
 * copy from fs while checksumming, otherwise like csum_partial
139
 */
140
 
141
unsigned int
142
csum_partial_copy_fromuser(const char *src, char *dst, int len, int sum)
143
{
144
        memcpy(dst, src, len);
145
        return csum_partial(dst, len, sum);
146
}
147
 
148
/*
149
 * copy from ds while checksumming, otherwise like csum_partial
150
 */
151
 
152
unsigned int
153
csum_partial_copy(const char *src, char *dst, int len, int sum)
154
{
155
        memcpy(dst, src, len);
156
        return csum_partial(dst, len, sum);
157
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.