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

Subversion Repositories or1k

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

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 199 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
static inline unsigned short from32to16(unsigned long x)
37
{
38
        /* add up 16-bit and 16-bit for 16+c bit */
39
        x = (x & 0xffff) + (x >> 16);
40
        /* add up carry.. */
41
        x = (x & 0xffff) + (x >> 16);
42
        return x;
43
}
44
 
45
static unsigned long do_csum(const unsigned char * buff, int len)
46
{
47
        int odd, count;
48
        unsigned long result = 0;
49
 
50
        if (len <= 0)
51
                goto out;
52
        odd = 1 & (unsigned long) buff;
53
        if (odd) {
54
                result = *buff;
55
                len--;
56
                buff++;
57
        }
58
        count = len >> 1;               /* nr of 16-bit words.. */
59
        if (count) {
60
                if (2 & (unsigned long) buff) {
61
                        result += *(unsigned short *) buff;
62
                        count--;
63
                        len -= 2;
64
                        buff += 2;
65
                }
66
                count >>= 1;            /* nr of 32-bit words.. */
67
                if (count) {
68
                        unsigned long carry = 0;
69
                        do {
70
                                unsigned long w = *(unsigned long *) buff;
71
                                count--;
72
                                buff += 4;
73
                                result += carry;
74
                                result += w;
75
                                carry = (w > result);
76
                        } while (count);
77
                        result += carry;
78
                        result = (result & 0xffff) + (result >> 16);
79
                }
80
                if (len & 2) {
81
                        result += *(unsigned short *) buff;
82
                        buff += 2;
83
                }
84
        }
85
        if (len & 1)
86
                result += (*buff << 8);
87
        result = from32to16(result);
88
        if (odd)
89
                result = ((result >> 8) & 0xff) | ((result & 0xff) << 8);
90
out:
91
        return result;
92
}
93
 
94
/*
95
 *      This is a version of ip_compute_csum() optimized for IP headers,
96
 *      which always checksum on 4 octet boundaries.
97
 */
98
unsigned short ip_fast_csum(unsigned char * iph, unsigned int ihl)
99
{
100
        return ~do_csum(iph,ihl*4);
101
}
102
 
103
/*
104
 * computes the checksum of a memory block at buff, length len,
105
 * and adds in "sum" (32-bit)
106
 *
107
 * returns a 32-bit number suitable for feeding into itself
108
 * or csum_tcpudp_magic
109
 *
110
 * this function must be called with even lengths, except
111
 * for the last fragment, which may be odd
112
 *
113
 * it's best to have buff aligned on a 32-bit boundary
114
 */
115
unsigned int csum_partial(const unsigned char * buff, int len, unsigned int sum)
116
{
117
        unsigned int result = do_csum(buff, len);
118
 
119
        /* add in old sum, and carry.. */
120
        result += sum;
121
        /* 16+c bits -> 16 bits */
122
        result = (result & 0xffff) + (result >> 16);
123
        return result;
124
}
125
 
126
/*
127
 * this routine is used for miscellaneous IP-like checksums, mainly
128
 * in icmp.c
129
 */
130
unsigned short ip_compute_csum(const unsigned char * buff, int len)
131
{
132
        return ~do_csum(buff,len);
133
}
134
 
135
/*
136
 * copy from fs while checksumming, otherwise like csum_partial
137
 */
138
 
139
unsigned int
140
csum_partial_copy_fromuser(const char *src, char *dst, int len, int sum)
141
{
142
        memcpy(dst, src, len);
143
        return csum_partial(dst, len, sum);
144
}
145
 
146
/*
147
 * copy from ds while checksumming, otherwise like csum_partial
148
 */
149
 
150
unsigned int
151
csum_partial_copy(const char *src, char *dst, int len, int sum)
152
{
153
        memcpy(dst, src, len);
154
        return csum_partial(dst, len, sum);
155
}

powered by: WebSVN 2.1.0

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