1b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0 21da177e4SLinus Torvalds /* 31da177e4SLinus Torvalds * Network Checksum & Copy routine 41da177e4SLinus Torvalds * 51da177e4SLinus Torvalds * Copyright (C) 1999, 2003-2004 Hewlett-Packard Co 61da177e4SLinus Torvalds * Stephane Eranian <eranian@hpl.hp.com> 71da177e4SLinus Torvalds * 81da177e4SLinus Torvalds * Most of the code has been imported from Linux/Alpha 91da177e4SLinus Torvalds */ 101da177e4SLinus Torvalds 111da177e4SLinus Torvalds #include <linux/module.h> 121da177e4SLinus Torvalds #include <linux/types.h> 131da177e4SLinus Torvalds #include <linux/string.h> 141da177e4SLinus Torvalds 15174e1ea8SAl Viro #include <net/checksum.h> 161da177e4SLinus Torvalds 171da177e4SLinus Torvalds /* 181da177e4SLinus Torvalds * XXX Fixme: those 2 inlines are meant for debugging and will go away 191da177e4SLinus Torvalds */ 201da177e4SLinus Torvalds static inline unsigned from64to16(unsigned long x)211da177e4SLinus Torvaldsshort from64to16(unsigned long x) 221da177e4SLinus Torvalds { 231da177e4SLinus Torvalds /* add up 32-bit words for 33 bits */ 241da177e4SLinus Torvalds x = (x & 0xffffffff) + (x >> 32); 251da177e4SLinus Torvalds /* add up 16-bit and 17-bit words for 17+c bits */ 261da177e4SLinus Torvalds x = (x & 0xffff) + (x >> 16); 271da177e4SLinus Torvalds /* add up 16-bit and 2-bit for 16+c bit */ 281da177e4SLinus Torvalds x = (x & 0xffff) + (x >> 16); 291da177e4SLinus Torvalds /* add up carry.. */ 301da177e4SLinus Torvalds x = (x & 0xffff) + (x >> 16); 311da177e4SLinus Torvalds return x; 321da177e4SLinus Torvalds } 331da177e4SLinus Torvalds 341da177e4SLinus Torvalds static inline do_csum_c(const unsigned char * buff,int len,unsigned int psum)351da177e4SLinus Torvaldsunsigned long do_csum_c(const unsigned char * buff, int len, unsigned int psum) 361da177e4SLinus Torvalds { 371da177e4SLinus Torvalds int odd, count; 381da177e4SLinus Torvalds unsigned long result = (unsigned long)psum; 391da177e4SLinus Torvalds 401da177e4SLinus Torvalds if (len <= 0) 411da177e4SLinus Torvalds goto out; 421da177e4SLinus Torvalds odd = 1 & (unsigned long) buff; 431da177e4SLinus Torvalds if (odd) { 441da177e4SLinus Torvalds result = *buff << 8; 451da177e4SLinus Torvalds len--; 461da177e4SLinus Torvalds buff++; 471da177e4SLinus Torvalds } 481da177e4SLinus Torvalds count = len >> 1; /* nr of 16-bit words.. */ 491da177e4SLinus Torvalds if (count) { 501da177e4SLinus Torvalds if (2 & (unsigned long) buff) { 511da177e4SLinus Torvalds result += *(unsigned short *) buff; 521da177e4SLinus Torvalds count--; 531da177e4SLinus Torvalds len -= 2; 541da177e4SLinus Torvalds buff += 2; 551da177e4SLinus Torvalds } 561da177e4SLinus Torvalds count >>= 1; /* nr of 32-bit words.. */ 571da177e4SLinus Torvalds if (count) { 581da177e4SLinus Torvalds if (4 & (unsigned long) buff) { 591da177e4SLinus Torvalds result += *(unsigned int *) buff; 601da177e4SLinus Torvalds count--; 611da177e4SLinus Torvalds len -= 4; 621da177e4SLinus Torvalds buff += 4; 631da177e4SLinus Torvalds } 641da177e4SLinus Torvalds count >>= 1; /* nr of 64-bit words.. */ 651da177e4SLinus Torvalds if (count) { 661da177e4SLinus Torvalds unsigned long carry = 0; 671da177e4SLinus Torvalds do { 681da177e4SLinus Torvalds unsigned long w = *(unsigned long *) buff; 691da177e4SLinus Torvalds count--; 701da177e4SLinus Torvalds buff += 8; 711da177e4SLinus Torvalds result += carry; 721da177e4SLinus Torvalds result += w; 731da177e4SLinus Torvalds carry = (w > result); 741da177e4SLinus Torvalds } while (count); 751da177e4SLinus Torvalds result += carry; 761da177e4SLinus Torvalds result = (result & 0xffffffff) + (result >> 32); 771da177e4SLinus Torvalds } 781da177e4SLinus Torvalds if (len & 4) { 791da177e4SLinus Torvalds result += *(unsigned int *) buff; 801da177e4SLinus Torvalds buff += 4; 811da177e4SLinus Torvalds } 821da177e4SLinus Torvalds } 831da177e4SLinus Torvalds if (len & 2) { 841da177e4SLinus Torvalds result += *(unsigned short *) buff; 851da177e4SLinus Torvalds buff += 2; 861da177e4SLinus Torvalds } 871da177e4SLinus Torvalds } 881da177e4SLinus Torvalds if (len & 1) 891da177e4SLinus Torvalds result += *buff; 901da177e4SLinus Torvalds 911da177e4SLinus Torvalds result = from64to16(result); 921da177e4SLinus Torvalds 931da177e4SLinus Torvalds if (odd) 941da177e4SLinus Torvalds result = ((result >> 8) & 0xff) | ((result & 0xff) << 8); 951da177e4SLinus Torvalds 961da177e4SLinus Torvalds out: 971da177e4SLinus Torvalds return result; 981da177e4SLinus Torvalds } 99