18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Network Checksum & Copy routine 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 1999, 2003-2004 Hewlett-Packard Co 68c2ecf20Sopenharmony_ci * Stephane Eranian <eranian@hpl.hp.com> 78c2ecf20Sopenharmony_ci * 88c2ecf20Sopenharmony_ci * Most of the code has been imported from Linux/Alpha 98c2ecf20Sopenharmony_ci */ 108c2ecf20Sopenharmony_ci 118c2ecf20Sopenharmony_ci#include <linux/module.h> 128c2ecf20Sopenharmony_ci#include <linux/types.h> 138c2ecf20Sopenharmony_ci#include <linux/string.h> 148c2ecf20Sopenharmony_ci 158c2ecf20Sopenharmony_ci#include <net/checksum.h> 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_ci/* 188c2ecf20Sopenharmony_ci * XXX Fixme: those 2 inlines are meant for debugging and will go away 198c2ecf20Sopenharmony_ci */ 208c2ecf20Sopenharmony_cistatic inline unsigned 218c2ecf20Sopenharmony_cishort from64to16(unsigned long x) 228c2ecf20Sopenharmony_ci{ 238c2ecf20Sopenharmony_ci /* add up 32-bit words for 33 bits */ 248c2ecf20Sopenharmony_ci x = (x & 0xffffffff) + (x >> 32); 258c2ecf20Sopenharmony_ci /* add up 16-bit and 17-bit words for 17+c bits */ 268c2ecf20Sopenharmony_ci x = (x & 0xffff) + (x >> 16); 278c2ecf20Sopenharmony_ci /* add up 16-bit and 2-bit for 16+c bit */ 288c2ecf20Sopenharmony_ci x = (x & 0xffff) + (x >> 16); 298c2ecf20Sopenharmony_ci /* add up carry.. */ 308c2ecf20Sopenharmony_ci x = (x & 0xffff) + (x >> 16); 318c2ecf20Sopenharmony_ci return x; 328c2ecf20Sopenharmony_ci} 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_cistatic inline 358c2ecf20Sopenharmony_ciunsigned long do_csum_c(const unsigned char * buff, int len, unsigned int psum) 368c2ecf20Sopenharmony_ci{ 378c2ecf20Sopenharmony_ci int odd, count; 388c2ecf20Sopenharmony_ci unsigned long result = (unsigned long)psum; 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_ci if (len <= 0) 418c2ecf20Sopenharmony_ci goto out; 428c2ecf20Sopenharmony_ci odd = 1 & (unsigned long) buff; 438c2ecf20Sopenharmony_ci if (odd) { 448c2ecf20Sopenharmony_ci result = *buff << 8; 458c2ecf20Sopenharmony_ci len--; 468c2ecf20Sopenharmony_ci buff++; 478c2ecf20Sopenharmony_ci } 488c2ecf20Sopenharmony_ci count = len >> 1; /* nr of 16-bit words.. */ 498c2ecf20Sopenharmony_ci if (count) { 508c2ecf20Sopenharmony_ci if (2 & (unsigned long) buff) { 518c2ecf20Sopenharmony_ci result += *(unsigned short *) buff; 528c2ecf20Sopenharmony_ci count--; 538c2ecf20Sopenharmony_ci len -= 2; 548c2ecf20Sopenharmony_ci buff += 2; 558c2ecf20Sopenharmony_ci } 568c2ecf20Sopenharmony_ci count >>= 1; /* nr of 32-bit words.. */ 578c2ecf20Sopenharmony_ci if (count) { 588c2ecf20Sopenharmony_ci if (4 & (unsigned long) buff) { 598c2ecf20Sopenharmony_ci result += *(unsigned int *) buff; 608c2ecf20Sopenharmony_ci count--; 618c2ecf20Sopenharmony_ci len -= 4; 628c2ecf20Sopenharmony_ci buff += 4; 638c2ecf20Sopenharmony_ci } 648c2ecf20Sopenharmony_ci count >>= 1; /* nr of 64-bit words.. */ 658c2ecf20Sopenharmony_ci if (count) { 668c2ecf20Sopenharmony_ci unsigned long carry = 0; 678c2ecf20Sopenharmony_ci do { 688c2ecf20Sopenharmony_ci unsigned long w = *(unsigned long *) buff; 698c2ecf20Sopenharmony_ci count--; 708c2ecf20Sopenharmony_ci buff += 8; 718c2ecf20Sopenharmony_ci result += carry; 728c2ecf20Sopenharmony_ci result += w; 738c2ecf20Sopenharmony_ci carry = (w > result); 748c2ecf20Sopenharmony_ci } while (count); 758c2ecf20Sopenharmony_ci result += carry; 768c2ecf20Sopenharmony_ci result = (result & 0xffffffff) + (result >> 32); 778c2ecf20Sopenharmony_ci } 788c2ecf20Sopenharmony_ci if (len & 4) { 798c2ecf20Sopenharmony_ci result += *(unsigned int *) buff; 808c2ecf20Sopenharmony_ci buff += 4; 818c2ecf20Sopenharmony_ci } 828c2ecf20Sopenharmony_ci } 838c2ecf20Sopenharmony_ci if (len & 2) { 848c2ecf20Sopenharmony_ci result += *(unsigned short *) buff; 858c2ecf20Sopenharmony_ci buff += 2; 868c2ecf20Sopenharmony_ci } 878c2ecf20Sopenharmony_ci } 888c2ecf20Sopenharmony_ci if (len & 1) 898c2ecf20Sopenharmony_ci result += *buff; 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_ci result = from64to16(result); 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ci if (odd) 948c2ecf20Sopenharmony_ci result = ((result >> 8) & 0xff) | ((result & 0xff) << 8); 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ciout: 978c2ecf20Sopenharmony_ci return result; 988c2ecf20Sopenharmony_ci} 99