162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Network Checksum & Copy routine 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 1999, 2003-2004 Hewlett-Packard Co 662306a36Sopenharmony_ci * Stephane Eranian <eranian@hpl.hp.com> 762306a36Sopenharmony_ci * 862306a36Sopenharmony_ci * Most of the code has been imported from Linux/Alpha 962306a36Sopenharmony_ci */ 1062306a36Sopenharmony_ci 1162306a36Sopenharmony_ci#include <linux/module.h> 1262306a36Sopenharmony_ci#include <linux/types.h> 1362306a36Sopenharmony_ci#include <linux/string.h> 1462306a36Sopenharmony_ci 1562306a36Sopenharmony_ci#include <net/checksum.h> 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_ci/* 1862306a36Sopenharmony_ci * XXX Fixme: those 2 inlines are meant for debugging and will go away 1962306a36Sopenharmony_ci */ 2062306a36Sopenharmony_cistatic inline unsigned 2162306a36Sopenharmony_cishort from64to16(unsigned long x) 2262306a36Sopenharmony_ci{ 2362306a36Sopenharmony_ci /* add up 32-bit words for 33 bits */ 2462306a36Sopenharmony_ci x = (x & 0xffffffff) + (x >> 32); 2562306a36Sopenharmony_ci /* add up 16-bit and 17-bit words for 17+c bits */ 2662306a36Sopenharmony_ci x = (x & 0xffff) + (x >> 16); 2762306a36Sopenharmony_ci /* add up 16-bit and 2-bit for 16+c bit */ 2862306a36Sopenharmony_ci x = (x & 0xffff) + (x >> 16); 2962306a36Sopenharmony_ci /* add up carry.. */ 3062306a36Sopenharmony_ci x = (x & 0xffff) + (x >> 16); 3162306a36Sopenharmony_ci return x; 3262306a36Sopenharmony_ci} 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_cistatic inline 3562306a36Sopenharmony_ciunsigned long do_csum_c(const unsigned char * buff, int len, unsigned int psum) 3662306a36Sopenharmony_ci{ 3762306a36Sopenharmony_ci int odd, count; 3862306a36Sopenharmony_ci unsigned long result = (unsigned long)psum; 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_ci if (len <= 0) 4162306a36Sopenharmony_ci goto out; 4262306a36Sopenharmony_ci odd = 1 & (unsigned long) buff; 4362306a36Sopenharmony_ci if (odd) { 4462306a36Sopenharmony_ci result = *buff << 8; 4562306a36Sopenharmony_ci len--; 4662306a36Sopenharmony_ci buff++; 4762306a36Sopenharmony_ci } 4862306a36Sopenharmony_ci count = len >> 1; /* nr of 16-bit words.. */ 4962306a36Sopenharmony_ci if (count) { 5062306a36Sopenharmony_ci if (2 & (unsigned long) buff) { 5162306a36Sopenharmony_ci result += *(unsigned short *) buff; 5262306a36Sopenharmony_ci count--; 5362306a36Sopenharmony_ci len -= 2; 5462306a36Sopenharmony_ci buff += 2; 5562306a36Sopenharmony_ci } 5662306a36Sopenharmony_ci count >>= 1; /* nr of 32-bit words.. */ 5762306a36Sopenharmony_ci if (count) { 5862306a36Sopenharmony_ci if (4 & (unsigned long) buff) { 5962306a36Sopenharmony_ci result += *(unsigned int *) buff; 6062306a36Sopenharmony_ci count--; 6162306a36Sopenharmony_ci len -= 4; 6262306a36Sopenharmony_ci buff += 4; 6362306a36Sopenharmony_ci } 6462306a36Sopenharmony_ci count >>= 1; /* nr of 64-bit words.. */ 6562306a36Sopenharmony_ci if (count) { 6662306a36Sopenharmony_ci unsigned long carry = 0; 6762306a36Sopenharmony_ci do { 6862306a36Sopenharmony_ci unsigned long w = *(unsigned long *) buff; 6962306a36Sopenharmony_ci count--; 7062306a36Sopenharmony_ci buff += 8; 7162306a36Sopenharmony_ci result += carry; 7262306a36Sopenharmony_ci result += w; 7362306a36Sopenharmony_ci carry = (w > result); 7462306a36Sopenharmony_ci } while (count); 7562306a36Sopenharmony_ci result += carry; 7662306a36Sopenharmony_ci result = (result & 0xffffffff) + (result >> 32); 7762306a36Sopenharmony_ci } 7862306a36Sopenharmony_ci if (len & 4) { 7962306a36Sopenharmony_ci result += *(unsigned int *) buff; 8062306a36Sopenharmony_ci buff += 4; 8162306a36Sopenharmony_ci } 8262306a36Sopenharmony_ci } 8362306a36Sopenharmony_ci if (len & 2) { 8462306a36Sopenharmony_ci result += *(unsigned short *) buff; 8562306a36Sopenharmony_ci buff += 2; 8662306a36Sopenharmony_ci } 8762306a36Sopenharmony_ci } 8862306a36Sopenharmony_ci if (len & 1) 8962306a36Sopenharmony_ci result += *buff; 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_ci result = from64to16(result); 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_ci if (odd) 9462306a36Sopenharmony_ci result = ((result >> 8) & 0xff) | ((result & 0xff) << 8); 9562306a36Sopenharmony_ci 9662306a36Sopenharmony_ciout: 9762306a36Sopenharmony_ci return result; 9862306a36Sopenharmony_ci} 99