162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */ 262306a36Sopenharmony_ci#ifndef __UM_CHECKSUM_H 362306a36Sopenharmony_ci#define __UM_CHECKSUM_H 462306a36Sopenharmony_ci 562306a36Sopenharmony_ci#include <linux/string.h> 662306a36Sopenharmony_ci#include <linux/in6.h> 762306a36Sopenharmony_ci#include <linux/uaccess.h> 862306a36Sopenharmony_ci 962306a36Sopenharmony_ci/* 1062306a36Sopenharmony_ci * computes the checksum of a memory block at buff, length len, 1162306a36Sopenharmony_ci * and adds in "sum" (32-bit) 1262306a36Sopenharmony_ci * 1362306a36Sopenharmony_ci * returns a 32-bit number suitable for feeding into itself 1462306a36Sopenharmony_ci * or csum_tcpudp_magic 1562306a36Sopenharmony_ci * 1662306a36Sopenharmony_ci * this function must be called with even lengths, except 1762306a36Sopenharmony_ci * for the last fragment, which may be odd 1862306a36Sopenharmony_ci * 1962306a36Sopenharmony_ci * it's best to have buff aligned on a 32-bit boundary 2062306a36Sopenharmony_ci */ 2162306a36Sopenharmony_ciextern __wsum csum_partial(const void *buff, int len, __wsum sum); 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_ci/** 2462306a36Sopenharmony_ci * csum_fold - Fold and invert a 32bit checksum. 2562306a36Sopenharmony_ci * sum: 32bit unfolded sum 2662306a36Sopenharmony_ci * 2762306a36Sopenharmony_ci * Fold a 32bit running checksum to 16bit and invert it. This is usually 2862306a36Sopenharmony_ci * the last step before putting a checksum into a packet. 2962306a36Sopenharmony_ci * Make sure not to mix with 64bit checksums. 3062306a36Sopenharmony_ci */ 3162306a36Sopenharmony_cistatic inline __sum16 csum_fold(__wsum sum) 3262306a36Sopenharmony_ci{ 3362306a36Sopenharmony_ci __asm__( 3462306a36Sopenharmony_ci " addl %1,%0\n" 3562306a36Sopenharmony_ci " adcl $0xffff,%0" 3662306a36Sopenharmony_ci : "=r" (sum) 3762306a36Sopenharmony_ci : "r" ((__force u32)sum << 16), 3862306a36Sopenharmony_ci "0" ((__force u32)sum & 0xffff0000) 3962306a36Sopenharmony_ci ); 4062306a36Sopenharmony_ci return (__force __sum16)(~(__force u32)sum >> 16); 4162306a36Sopenharmony_ci} 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_ci/** 4462306a36Sopenharmony_ci * csum_tcpup_nofold - Compute an IPv4 pseudo header checksum. 4562306a36Sopenharmony_ci * @saddr: source address 4662306a36Sopenharmony_ci * @daddr: destination address 4762306a36Sopenharmony_ci * @len: length of packet 4862306a36Sopenharmony_ci * @proto: ip protocol of packet 4962306a36Sopenharmony_ci * @sum: initial sum to be added in (32bit unfolded) 5062306a36Sopenharmony_ci * 5162306a36Sopenharmony_ci * Returns the pseudo header checksum the input data. Result is 5262306a36Sopenharmony_ci * 32bit unfolded. 5362306a36Sopenharmony_ci */ 5462306a36Sopenharmony_cistatic inline __wsum 5562306a36Sopenharmony_cicsum_tcpudp_nofold(__be32 saddr, __be32 daddr, __u32 len, 5662306a36Sopenharmony_ci __u8 proto, __wsum sum) 5762306a36Sopenharmony_ci{ 5862306a36Sopenharmony_ci asm(" addl %1, %0\n" 5962306a36Sopenharmony_ci " adcl %2, %0\n" 6062306a36Sopenharmony_ci " adcl %3, %0\n" 6162306a36Sopenharmony_ci " adcl $0, %0\n" 6262306a36Sopenharmony_ci : "=r" (sum) 6362306a36Sopenharmony_ci : "g" (daddr), "g" (saddr), "g" ((len + proto) << 8), "0" (sum)); 6462306a36Sopenharmony_ci return sum; 6562306a36Sopenharmony_ci} 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_ci/* 6862306a36Sopenharmony_ci * computes the checksum of the TCP/UDP pseudo-header 6962306a36Sopenharmony_ci * returns a 16-bit checksum, already complemented 7062306a36Sopenharmony_ci */ 7162306a36Sopenharmony_cistatic inline __sum16 csum_tcpudp_magic(__be32 saddr, __be32 daddr, 7262306a36Sopenharmony_ci __u32 len, __u8 proto, 7362306a36Sopenharmony_ci __wsum sum) 7462306a36Sopenharmony_ci{ 7562306a36Sopenharmony_ci return csum_fold(csum_tcpudp_nofold(saddr,daddr,len,proto,sum)); 7662306a36Sopenharmony_ci} 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_ci/** 7962306a36Sopenharmony_ci * ip_fast_csum - Compute the IPv4 header checksum efficiently. 8062306a36Sopenharmony_ci * iph: ipv4 header 8162306a36Sopenharmony_ci * ihl: length of header / 4 8262306a36Sopenharmony_ci */ 8362306a36Sopenharmony_cistatic inline __sum16 ip_fast_csum(const void *iph, unsigned int ihl) 8462306a36Sopenharmony_ci{ 8562306a36Sopenharmony_ci unsigned int sum; 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_ci asm( " movl (%1), %0\n" 8862306a36Sopenharmony_ci " subl $4, %2\n" 8962306a36Sopenharmony_ci " jbe 2f\n" 9062306a36Sopenharmony_ci " addl 4(%1), %0\n" 9162306a36Sopenharmony_ci " adcl 8(%1), %0\n" 9262306a36Sopenharmony_ci " adcl 12(%1), %0\n" 9362306a36Sopenharmony_ci "1: adcl 16(%1), %0\n" 9462306a36Sopenharmony_ci " lea 4(%1), %1\n" 9562306a36Sopenharmony_ci " decl %2\n" 9662306a36Sopenharmony_ci " jne 1b\n" 9762306a36Sopenharmony_ci " adcl $0, %0\n" 9862306a36Sopenharmony_ci " movl %0, %2\n" 9962306a36Sopenharmony_ci " shrl $16, %0\n" 10062306a36Sopenharmony_ci " addw %w2, %w0\n" 10162306a36Sopenharmony_ci " adcl $0, %0\n" 10262306a36Sopenharmony_ci " notl %0\n" 10362306a36Sopenharmony_ci "2:" 10462306a36Sopenharmony_ci /* Since the input registers which are loaded with iph and ipl 10562306a36Sopenharmony_ci are modified, we must also specify them as outputs, or gcc 10662306a36Sopenharmony_ci will assume they contain their original values. */ 10762306a36Sopenharmony_ci : "=r" (sum), "=r" (iph), "=r" (ihl) 10862306a36Sopenharmony_ci : "1" (iph), "2" (ihl) 10962306a36Sopenharmony_ci : "memory"); 11062306a36Sopenharmony_ci return (__force __sum16)sum; 11162306a36Sopenharmony_ci} 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_ci#ifdef CONFIG_X86_32 11462306a36Sopenharmony_ci# include "checksum_32.h" 11562306a36Sopenharmony_ci#else 11662306a36Sopenharmony_ci# include "checksum_64.h" 11762306a36Sopenharmony_ci#endif 11862306a36Sopenharmony_ci 11962306a36Sopenharmony_ci#endif 120