forked from torvalds/linux
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add a generic (unoptimized) implementation of checksum.c in pure C for use by all architectures that cannot be bother with implementing their own version. Based on microblaze code by Michal Simek <[email protected]> Cc: Michal Simek <[email protected]> Signed-off-by: Remis Lima Baima <[email protected]> Signed-off-by: Arnd Bergmann <[email protected]>
- Loading branch information
Showing
3 changed files
with
274 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,79 @@ | ||
#ifndef __ASM_GENERIC_CHECKSUM_H | ||
#define __ASM_GENERIC_CHECKSUM_H | ||
|
||
/* | ||
* computes the checksum of a memory block at buff, length len, | ||
* and adds in "sum" (32-bit) | ||
* | ||
* returns a 32-bit number suitable for feeding into itself | ||
* or csum_tcpudp_magic | ||
* | ||
* this function must be called with even lengths, except | ||
* for the last fragment, which may be odd | ||
* | ||
* it's best to have buff aligned on a 32-bit boundary | ||
*/ | ||
extern __wsum csum_partial(const void *buff, int len, __wsum sum); | ||
|
||
/* | ||
* the same as csum_partial, but copies from src while it | ||
* checksums | ||
* | ||
* here even more important to align src and dst on a 32-bit (or even | ||
* better 64-bit) boundary | ||
*/ | ||
extern __wsum csum_partial_copy(const void *src, void *dst, int len, __wsum sum); | ||
|
||
/* | ||
* the same as csum_partial_copy, but copies from user space. | ||
* | ||
* here even more important to align src and dst on a 32-bit (or even | ||
* better 64-bit) boundary | ||
*/ | ||
extern __wsum csum_partial_copy_from_user(const void __user *src, void *dst, | ||
int len, __wsum sum, int *csum_err); | ||
|
||
#define csum_partial_copy_nocheck(src, dst, len, sum) \ | ||
csum_partial_copy((src), (dst), (len), (sum)) | ||
|
||
/* | ||
* This is a version of ip_compute_csum() optimized for IP headers, | ||
* which always checksum on 4 octet boundaries. | ||
*/ | ||
extern __sum16 ip_fast_csum(const void *iph, unsigned int ihl); | ||
|
||
/* | ||
* Fold a partial checksum | ||
*/ | ||
static inline __sum16 csum_fold(__wsum csum) | ||
{ | ||
u32 sum = (__force u32)csum; | ||
sum = (sum & 0xffff) + (sum >> 16); | ||
sum = (sum & 0xffff) + (sum >> 16); | ||
return (__force __sum16)~sum; | ||
} | ||
|
||
#ifndef csum_tcpudp_nofold | ||
/* | ||
* computes the checksum of the TCP/UDP pseudo-header | ||
* returns a 16-bit checksum, already complemented | ||
*/ | ||
extern __wsum | ||
csum_tcpudp_nofold(__be32 saddr, __be32 daddr, unsigned short len, | ||
unsigned short proto, __wsum sum); | ||
#endif | ||
|
||
static inline __sum16 | ||
csum_tcpudp_magic(__be32 saddr, __be32 daddr, unsigned short len, | ||
unsigned short proto, __wsum sum) | ||
{ | ||
return csum_fold(csum_tcpudp_nofold(saddr, daddr, len, proto, sum)); | ||
} | ||
|
||
/* | ||
* this routine is used for miscellaneous IP-like checksums, mainly | ||
* in icmp.c | ||
*/ | ||
extern __sum16 ip_compute_csum(const void *buff, int len); | ||
|
||
#endif /* __ASM_GENERIC_CHECKSUM_H */ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,193 @@ | ||
/* | ||
* | ||
* INET An implementation of the TCP/IP protocol suite for the LINUX | ||
* operating system. INET is implemented using the BSD Socket | ||
* interface as the means of communication with the user level. | ||
* | ||
* IP/TCP/UDP checksumming routines | ||
* | ||
* Authors: Jorge Cwik, <[email protected]> | ||
* Arnt Gulbrandsen, <[email protected]> | ||
* Tom May, <[email protected]> | ||
* Andreas Schwab, <[email protected]> | ||
* Lots of code moved from tcp.c and ip.c; see those files | ||
* for more names. | ||
* | ||
* 03/02/96 Jes Sorensen, Andreas Schwab, Roman Hodek: | ||
* Fixed some nasty bugs, causing some horrible crashes. | ||
* A: At some points, the sum (%0) was used as | ||
* length-counter instead of the length counter | ||
* (%1). Thanks to Roman Hodek for pointing this out. | ||
* B: GCC seems to mess up if one uses too many | ||
* data-registers to hold input values and one tries to | ||
* specify d0 and d1 as scratch registers. Letting gcc | ||
* choose these registers itself solves the problem. | ||
* | ||
* This program is free software; you can redistribute it and/or | ||
* modify it under the terms of the GNU General Public License | ||
* as published by the Free Software Foundation; either version | ||
* 2 of the License, or (at your option) any later version. | ||
*/ | ||
|
||
/* Revised by Kenneth Albanowski for m68knommu. Basic problem: unaligned access | ||
kills, so most of the assembly has to go. */ | ||
|
||
#include <linux/module.h> | ||
#include <net/checksum.h> | ||
|
||
#include <asm/byteorder.h> | ||
|
||
static inline unsigned short from32to16(unsigned long x) | ||
{ | ||
/* add up 16-bit and 16-bit for 16+c bit */ | ||
x = (x & 0xffff) + (x >> 16); | ||
/* add up carry.. */ | ||
x = (x & 0xffff) + (x >> 16); | ||
return x; | ||
} | ||
|
||
static unsigned int do_csum(const unsigned char *buff, int len) | ||
{ | ||
int odd, count; | ||
unsigned long result = 0; | ||
|
||
if (len <= 0) | ||
goto out; | ||
odd = 1 & (unsigned long) buff; | ||
if (odd) { | ||
result = *buff; | ||
len--; | ||
buff++; | ||
} | ||
count = len >> 1; /* nr of 16-bit words.. */ | ||
if (count) { | ||
if (2 & (unsigned long) buff) { | ||
result += *(unsigned short *) buff; | ||
count--; | ||
len -= 2; | ||
buff += 2; | ||
} | ||
count >>= 1; /* nr of 32-bit words.. */ | ||
if (count) { | ||
unsigned long carry = 0; | ||
do { | ||
unsigned long w = *(unsigned long *) buff; | ||
count--; | ||
buff += 4; | ||
result += carry; | ||
result += w; | ||
carry = (w > result); | ||
} while (count); | ||
result += carry; | ||
result = (result & 0xffff) + (result >> 16); | ||
} | ||
if (len & 2) { | ||
result += *(unsigned short *) buff; | ||
buff += 2; | ||
} | ||
} | ||
if (len & 1) | ||
result += (*buff << 8); | ||
result = from32to16(result); | ||
if (odd) | ||
result = ((result >> 8) & 0xff) | ((result & 0xff) << 8); | ||
out: | ||
return result; | ||
} | ||
|
||
/* | ||
* This is a version of ip_compute_csum() optimized for IP headers, | ||
* which always checksum on 4 octet boundaries. | ||
*/ | ||
__sum16 ip_fast_csum(const void *iph, unsigned int ihl) | ||
{ | ||
return (__force __sum16)~do_csum(iph, ihl*4); | ||
} | ||
EXPORT_SYMBOL(ip_fast_csum); | ||
|
||
/* | ||
* computes the checksum of a memory block at buff, length len, | ||
* and adds in "sum" (32-bit) | ||
* | ||
* returns a 32-bit number suitable for feeding into itself | ||
* or csum_tcpudp_magic | ||
* | ||
* this function must be called with even lengths, except | ||
* for the last fragment, which may be odd | ||
* | ||
* it's best to have buff aligned on a 32-bit boundary | ||
*/ | ||
__wsum csum_partial(const void *buff, int len, __wsum wsum) | ||
{ | ||
unsigned int sum = (__force unsigned int)wsum; | ||
unsigned int result = do_csum(buff, len); | ||
|
||
/* add in old sum, and carry.. */ | ||
result += sum; | ||
if (sum > result) | ||
result += 1; | ||
return (__force __wsum)result; | ||
} | ||
EXPORT_SYMBOL(csum_partial); | ||
|
||
/* | ||
* this routine is used for miscellaneous IP-like checksums, mainly | ||
* in icmp.c | ||
*/ | ||
__sum16 ip_compute_csum(const void *buff, int len) | ||
{ | ||
return (__force __sum16)~do_csum(buff, len); | ||
} | ||
EXPORT_SYMBOL(ip_compute_csum); | ||
|
||
/* | ||
* copy from fs while checksumming, otherwise like csum_partial | ||
*/ | ||
__wsum | ||
csum_partial_copy_from_user(const void __user *src, void *dst, int len, | ||
__wsum sum, int *csum_err) | ||
{ | ||
int missing; | ||
|
||
missing = __copy_from_user(dst, src, len); | ||
if (missing) { | ||
memset(dst + len - missing, 0, missing); | ||
*csum_err = -EFAULT; | ||
} else | ||
*csum_err = 0; | ||
|
||
return csum_partial(dst, len, sum); | ||
} | ||
EXPORT_SYMBOL(csum_partial_copy_from_user); | ||
|
||
/* | ||
* copy from ds while checksumming, otherwise like csum_partial | ||
*/ | ||
__wsum | ||
csum_partial_copy(const void *src, void *dst, int len, __wsum sum) | ||
{ | ||
memcpy(dst, src, len); | ||
return csum_partial(dst, len, sum); | ||
} | ||
EXPORT_SYMBOL(csum_partial_copy); | ||
|
||
#ifndef csum_tcpudp_nofold | ||
__wsum csum_tcpudp_nofold(__be32 saddr, __be32 daddr, | ||
unsigned short len, | ||
unsigned short proto, | ||
__wsum sum) | ||
{ | ||
unsigned long long s = (__force u32)sum; | ||
|
||
s += (__force u32)saddr; | ||
s += (__force u32)daddr; | ||
#ifdef __BIG_ENDIAN | ||
s += proto + len; | ||
#else | ||
s += (proto + len) << 8; | ||
#endif | ||
s += (s >> 32); | ||
return (__force __wsum)s; | ||
} | ||
EXPORT_SYMBOL(csum_tcpudp_nofold); | ||
#endif |