diff options
author | Paul Mackerras <paulus@samba.org> | 2007-05-07 23:37:51 -0400 |
---|---|---|
committer | Paul Mackerras <paulus@samba.org> | 2007-05-07 23:37:51 -0400 |
commit | 02bbc0f09c90cefdb2837605c96a66c5ce4ba2e1 (patch) | |
tree | 04ef573cd4de095c500c9fc3477f4278c0b36300 /arch/blackfin/lib/checksum.c | |
parent | 7487a2245b8841c77ba9db406cf99a483b9334e9 (diff) | |
parent | 5b94f675f57e4ff16c8fda09088d7480a84dcd91 (diff) |
Merge branch 'linux-2.6'
Diffstat (limited to 'arch/blackfin/lib/checksum.c')
-rw-r--r-- | arch/blackfin/lib/checksum.c | 140 |
1 files changed, 140 insertions, 0 deletions
diff --git a/arch/blackfin/lib/checksum.c b/arch/blackfin/lib/checksum.c new file mode 100644 index 000000000000..42768e0c80ca --- /dev/null +++ b/arch/blackfin/lib/checksum.c | |||
@@ -0,0 +1,140 @@ | |||
1 | /* | ||
2 | * File: arch/blackfin/lib/checksum.c | ||
3 | * Based on: none - original work | ||
4 | * Author: | ||
5 | * | ||
6 | * Created: | ||
7 | * Description: An implementation of the TCP/IP protocol suite for the LINUX | ||
8 | * operating system. INET is implemented using the BSD Socket | ||
9 | * interface as the means of communication with the user level. | ||
10 | * | ||
11 | * Modified: | ||
12 | * Copyright 2004-2006 Analog Devices Inc. | ||
13 | * | ||
14 | * Bugs: Enter bugs at http://blackfin.uclinux.org/ | ||
15 | * | ||
16 | * This program is free software; you can redistribute it and/or modify | ||
17 | * it under the terms of the GNU General Public License as published by | ||
18 | * the Free Software Foundation; either version 2 of the License, or | ||
19 | * (at your option) any later version. | ||
20 | * | ||
21 | * This program is distributed in the hope that it will be useful, | ||
22 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
23 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
24 | * GNU General Public License for more details. | ||
25 | * | ||
26 | * You should have received a copy of the GNU General Public License | ||
27 | * along with this program; if not, see the file COPYING, or write | ||
28 | * to the Free Software Foundation, Inc., | ||
29 | * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | ||
30 | */ | ||
31 | |||
32 | #include <net/checksum.h> | ||
33 | #include <asm/checksum.h> | ||
34 | |||
35 | #ifdef CONFIG_IP_CHECKSUM_L1 | ||
36 | static unsigned short do_csum(const unsigned char *buff, int len)__attribute__((l1_text)); | ||
37 | #endif | ||
38 | |||
39 | static unsigned short do_csum(const unsigned char *buff, int len) | ||
40 | { | ||
41 | register unsigned long sum = 0; | ||
42 | int swappem = 0; | ||
43 | |||
44 | if (1 & (unsigned long)buff) { | ||
45 | sum = *buff << 8; | ||
46 | buff++; | ||
47 | len--; | ||
48 | ++swappem; | ||
49 | } | ||
50 | |||
51 | while (len > 1) { | ||
52 | sum += *(unsigned short *)buff; | ||
53 | buff += 2; | ||
54 | len -= 2; | ||
55 | } | ||
56 | |||
57 | if (len > 0) | ||
58 | sum += *buff; | ||
59 | |||
60 | /* Fold 32-bit sum to 16 bits */ | ||
61 | while (sum >> 16) | ||
62 | sum = (sum & 0xffff) + (sum >> 16); | ||
63 | |||
64 | if (swappem) | ||
65 | sum = ((sum & 0xff00) >> 8) + ((sum & 0x00ff) << 8); | ||
66 | |||
67 | return sum; | ||
68 | |||
69 | } | ||
70 | |||
71 | /* | ||
72 | * This is a version of ip_compute_csum() optimized for IP headers, | ||
73 | * which always checksum on 4 octet boundaries. | ||
74 | */ | ||
75 | unsigned short ip_fast_csum(unsigned char *iph, unsigned int ihl) | ||
76 | { | ||
77 | return ~do_csum(iph, ihl * 4); | ||
78 | } | ||
79 | |||
80 | /* | ||
81 | * computes the checksum of a memory block at buff, length len, | ||
82 | * and adds in "sum" (32-bit) | ||
83 | * | ||
84 | * returns a 32-bit number suitable for feeding into itself | ||
85 | * or csum_tcpudp_magic | ||
86 | * | ||
87 | * this function must be called with even lengths, except | ||
88 | * for the last fragment, which may be odd | ||
89 | * | ||
90 | * it's best to have buff aligned on a 32-bit boundary | ||
91 | */ | ||
92 | unsigned int csum_partial(const unsigned char *buff, int len, unsigned int sum) | ||
93 | { | ||
94 | /* | ||
95 | * Just in case we get nasty checksum data... | ||
96 | * Like 0xffff6ec3 in the case of our IPv6 multicast header. | ||
97 | * We fold to begin with, as well as at the end. | ||
98 | */ | ||
99 | sum = (sum & 0xffff) + (sum >> 16); | ||
100 | |||
101 | sum += do_csum(buff, len); | ||
102 | |||
103 | sum = (sum & 0xffff) + (sum >> 16); | ||
104 | |||
105 | return sum; | ||
106 | } | ||
107 | |||
108 | /* | ||
109 | * this routine is used for miscellaneous IP-like checksums, mainly | ||
110 | * in icmp.c | ||
111 | */ | ||
112 | unsigned short ip_compute_csum(const unsigned char *buff, int len) | ||
113 | { | ||
114 | return ~do_csum(buff, len); | ||
115 | } | ||
116 | |||
117 | /* | ||
118 | * copy from fs while checksumming, otherwise like csum_partial | ||
119 | */ | ||
120 | |||
121 | unsigned int | ||
122 | csum_partial_copy_from_user(const unsigned char *src, unsigned char *dst, | ||
123 | int len, int sum, int *csum_err) | ||
124 | { | ||
125 | if (csum_err) | ||
126 | *csum_err = 0; | ||
127 | memcpy(dst, src, len); | ||
128 | return csum_partial(dst, len, sum); | ||
129 | } | ||
130 | |||
131 | /* | ||
132 | * copy from ds while checksumming, otherwise like csum_partial | ||
133 | */ | ||
134 | |||
135 | unsigned int csum_partial_copy(const unsigned char *src, unsigned char *dst, | ||
136 | int len, int sum) | ||
137 | { | ||
138 | memcpy(dst, src, len); | ||
139 | return csum_partial(dst, len, sum); | ||
140 | } | ||