1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Network Checksum & Copy routine 4 * 5 * Copyright (C) 1999, 2003-2004 Hewlett-Packard Co 6 * Stephane Eranian <eranian@hpl.hp.com> 7 * 8 * Most of the code has been imported from Linux/Alpha 9 */ 10 11 #include <linux/module.h> 12 #include <linux/types.h> 13 #include <linux/string.h> 14 15 #include <net/checksum.h> 16 17 /* 18 * XXX Fixme: those 2 inlines are meant for debugging and will go away 19 */ 20 static inline unsigned from64to16(unsigned long x)21short from64to16(unsigned long x) 22 { 23 /* add up 32-bit words for 33 bits */ 24 x = (x & 0xffffffff) + (x >> 32); 25 /* add up 16-bit and 17-bit words for 17+c bits */ 26 x = (x & 0xffff) + (x >> 16); 27 /* add up 16-bit and 2-bit for 16+c bit */ 28 x = (x & 0xffff) + (x >> 16); 29 /* add up carry.. */ 30 x = (x & 0xffff) + (x >> 16); 31 return x; 32 } 33 34 static inline do_csum_c(const unsigned char * buff,int len,unsigned int psum)35unsigned long do_csum_c(const unsigned char * buff, int len, unsigned int psum) 36 { 37 int odd, count; 38 unsigned long result = (unsigned long)psum; 39 40 if (len <= 0) 41 goto out; 42 odd = 1 & (unsigned long) buff; 43 if (odd) { 44 result = *buff << 8; 45 len--; 46 buff++; 47 } 48 count = len >> 1; /* nr of 16-bit words.. */ 49 if (count) { 50 if (2 & (unsigned long) buff) { 51 result += *(unsigned short *) buff; 52 count--; 53 len -= 2; 54 buff += 2; 55 } 56 count >>= 1; /* nr of 32-bit words.. */ 57 if (count) { 58 if (4 & (unsigned long) buff) { 59 result += *(unsigned int *) buff; 60 count--; 61 len -= 4; 62 buff += 4; 63 } 64 count >>= 1; /* nr of 64-bit words.. */ 65 if (count) { 66 unsigned long carry = 0; 67 do { 68 unsigned long w = *(unsigned long *) buff; 69 count--; 70 buff += 8; 71 result += carry; 72 result += w; 73 carry = (w > result); 74 } while (count); 75 result += carry; 76 result = (result & 0xffffffff) + (result >> 32); 77 } 78 if (len & 4) { 79 result += *(unsigned int *) buff; 80 buff += 4; 81 } 82 } 83 if (len & 2) { 84 result += *(unsigned short *) buff; 85 buff += 2; 86 } 87 } 88 if (len & 1) 89 result += *buff; 90 91 result = from64to16(result); 92 93 if (odd) 94 result = ((result >> 8) & 0xff) | ((result & 0xff) << 8); 95 96 out: 97 return result; 98 } 99