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

Subversion Repositories or1k

[/] [or1k/] [trunk/] [rc203soc/] [sw/] [uClinux/] [arch/] [i960/] [lib/] [checksum.c] - Blame information for rev 1765

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 1623 jcastillo
/*
2
 * INET         An implementation of the TCP/IP protocol suite for the LINUX
3
 *              operating system.
4
 *
5
 *              IP/TCP/UDP checksumming routines
6
 *
7
 * Authors:     Keith Adams,    <kma@cse.ogi.edu>
8
 *              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
 */
16
 
17
#include <net/checksum.h>
18
 
19
#if 1
20
static unsigned long do_csum(const unsigned char * buff, int len)
21
{
22
        int odd, count;
23
        unsigned long result = 0;
24
 
25
        if (len <= 0)
26
                goto out;
27
        odd = 1 & (unsigned long) buff;
28
        if (odd) {
29
                result = *buff;
30
                len--;
31
                buff++;
32
        }
33
        count = len >> 1;               /* nr of 16-bit words.. */
34
        if (count) {
35
                if (2 & (unsigned long) buff) {
36
                        result += *(unsigned short *) buff;
37
                        count--;
38
                        len -= 2;
39
                        buff += 2;
40
                }
41
                count >>= 1;            /* nr of 32-bit words.. */
42
                if (count) {
43
#if 1
44
                        unsigned long carry = 0;
45
                        do {
46
                                unsigned long w = *(unsigned long *) buff;
47
                                count--;
48
                                buff += 4;
49
                                result += carry;
50
                                result += w;
51
                                carry = (w > result);
52
                        } while (count);
53
                        result += carry;
54
#else
55
                        asm("cmpo       0, 1");         /* clear carry */
56
                        do {
57
                                unsigned long w = *(unsigned long*) buff;
58
                                count--;
59
                                buff += 4;
60
                                asm("addc       0, %0, %0\n\t"  /* r += carry */
61
                                    "cmpo       0, 1\n\t"       /* reset c */
62
                                    "addc       %1, %0, %0"     /* r += w */
63
                                    : "=&r"(result)
64
                                    : "r"(w), "0"(result));
65
                        } while (count);
66
                        asm("addc       0, %0, %0"      /* result += carry */
67
                            : "=r"(result) : "0"(result));
68
#endif
69
                        result = (result & 0xffff) + (result >> 16);
70
                }
71
                if (len & 2) {
72
                        result += *(unsigned short *) buff;
73
                        buff += 2;
74
                }
75
        }
76
        if (len & 1)
77
                result += *buff;
78
 
79
        result = from32to16(result);
80
        if (odd)
81
                return ntohs(result);
82
out:
83
        return result;
84
}
85
#else
86
 
87
/*
88
 * Naive implementation stolen from Stevens
89
 */
90
static unsigned long do_csum(const unsigned char * buff, int len)
91
{
92
        long sum=0;
93
 
94
        while (len > 1) {
95
                sum += *((unsigned short*)buff)++;
96
                if (sum & (1<<31))
97
                        sum = (sum & 0xffff);
98
                len -= 2;
99
        }
100
 
101
        if (len)
102
                sum += (unsigned short) *buff;
103
 
104
        while (sum >> 16)
105
                sum = (sum & 0xffff) + (sum >> 16);
106
 
107
        return sum;
108
}
109
#endif
110
 
111
/*
112
 *      This is a version of ip_compute_csum() optimized for IP headers,
113
 *      which always checksum on 4 octet boundaries.
114
 */
115
unsigned short ip_fast_csum(unsigned char * iph, unsigned int ihl)
116
{
117
        return ~do_csum(iph,ihl*4);
118
}
119
 
120
/*
121
 * computes the checksum of a memory block at buff, length len,
122
 * and adds in "sum" (32-bit)
123
 *
124
 * returns a 32-bit number suitable for feeding into itself
125
 * or csum_tcpudp_magic
126
 *
127
 * this function must be called with even lengths, except
128
 * for the last fragment, which may be odd
129
 *
130
 * it's best to have buff aligned on a 32-bit boundary
131
 */
132
unsigned int csum_partial(const unsigned char * buff, int len, unsigned int sum)
133
{
134
        unsigned int result = do_csum(buff, len);
135
 
136
        /* add in old sum, and carry.. */
137
        result += sum;
138
        /* 16+c bits -> 16 bits */
139
        result = (result & 0xffff) + (result >> 16);
140
        return result;
141
}
142
 
143
/*
144
 * this routine is used for miscellaneous IP-like checksums, mainly
145
 * in icmp.c
146
 */
147
unsigned short ip_compute_csum(const unsigned char * buff, int len)
148
{
149
        return ~do_csum(buff,len);
150
}
151
 
152
 
153
/*
154
 * copy from fs while checksumming, otherwise like csum_partial
155
 */
156
 
157
unsigned int
158
csum_partial_copy_fromuser(const char *src, char *dst, int len, int sum)
159
{
160
        memcpy(dst, src, len);
161
        return csum_partial(dst, len, sum);
162
}
163
/*
164
 * copy from ds while checksumming, otherwise like csum_partial
165
 */
166
 
167
unsigned int
168
csum_partial_copy(const char *src, char *dst, int len, int sum)
169
{
170
        memcpy(dst, src, len);
171
        return csum_partial(dst, len, sum);
172
}

powered by: WebSVN 2.1.0

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