|  | /* SPDX-License-Identifier: GPL-2.0 */ | 
|  | #ifndef __UM_CHECKSUM_H | 
|  | #define __UM_CHECKSUM_H | 
|  |  | 
|  | #include <linux/string.h> | 
|  | #include <linux/in6.h> | 
|  | #include <linux/uaccess.h> | 
|  |  | 
|  | /* | 
|  | * computes the checksum of a memory block at buff, length len, | 
|  | * and adds in "sum" (32-bit) | 
|  | * | 
|  | * returns a 32-bit number suitable for feeding into itself | 
|  | * or csum_tcpudp_magic | 
|  | * | 
|  | * this function must be called with even lengths, except | 
|  | * for the last fragment, which may be odd | 
|  | * | 
|  | * it's best to have buff aligned on a 32-bit boundary | 
|  | */ | 
|  | extern __wsum csum_partial(const void *buff, int len, __wsum sum); | 
|  |  | 
|  | /** | 
|  | * csum_fold - Fold and invert a 32bit checksum. | 
|  | * sum: 32bit unfolded sum | 
|  | * | 
|  | * Fold a 32bit running checksum to 16bit and invert it. This is usually | 
|  | * the last step before putting a checksum into a packet. | 
|  | * Make sure not to mix with 64bit checksums. | 
|  | */ | 
|  | static inline __sum16 csum_fold(__wsum sum) | 
|  | { | 
|  | __asm__( | 
|  | "  addl %1,%0\n" | 
|  | "  adcl $0xffff,%0" | 
|  | : "=r" (sum) | 
|  | : "r" ((__force u32)sum << 16), | 
|  | "0" ((__force u32)sum & 0xffff0000) | 
|  | ); | 
|  | return (__force __sum16)(~(__force u32)sum >> 16); | 
|  | } | 
|  |  | 
|  | /** | 
|  | * csum_tcpup_nofold - Compute an IPv4 pseudo header checksum. | 
|  | * @saddr: source address | 
|  | * @daddr: destination address | 
|  | * @len: length of packet | 
|  | * @proto: ip protocol of packet | 
|  | * @sum: initial sum to be added in (32bit unfolded) | 
|  | * | 
|  | * Returns the pseudo header checksum the input data. Result is | 
|  | * 32bit unfolded. | 
|  | */ | 
|  | static inline __wsum | 
|  | csum_tcpudp_nofold(__be32 saddr, __be32 daddr, __u32 len, | 
|  | __u8 proto, __wsum sum) | 
|  | { | 
|  | asm("  addl %1, %0\n" | 
|  | "  adcl %2, %0\n" | 
|  | "  adcl %3, %0\n" | 
|  | "  adcl $0, %0\n" | 
|  | : "=r" (sum) | 
|  | : "g" (daddr), "g" (saddr), "g" ((len + proto) << 8), "0" (sum)); | 
|  | return sum; | 
|  | } | 
|  |  | 
|  | /* | 
|  | * computes the checksum of the TCP/UDP pseudo-header | 
|  | * returns a 16-bit checksum, already complemented | 
|  | */ | 
|  | static inline __sum16 csum_tcpudp_magic(__be32 saddr, __be32 daddr, | 
|  | __u32 len, __u8 proto, | 
|  | __wsum sum) | 
|  | { | 
|  | return csum_fold(csum_tcpudp_nofold(saddr,daddr,len,proto,sum)); | 
|  | } | 
|  |  | 
|  | /** | 
|  | * ip_fast_csum - Compute the IPv4 header checksum efficiently. | 
|  | * iph: ipv4 header | 
|  | * ihl: length of header / 4 | 
|  | */ | 
|  | static inline __sum16 ip_fast_csum(const void *iph, unsigned int ihl) | 
|  | { | 
|  | unsigned int sum; | 
|  |  | 
|  | asm(	"  movl (%1), %0\n" | 
|  | "  subl $4, %2\n" | 
|  | "  jbe 2f\n" | 
|  | "  addl 4(%1), %0\n" | 
|  | "  adcl 8(%1), %0\n" | 
|  | "  adcl 12(%1), %0\n" | 
|  | "1: adcl 16(%1), %0\n" | 
|  | "  lea 4(%1), %1\n" | 
|  | "  decl %2\n" | 
|  | "  jne	1b\n" | 
|  | "  adcl $0, %0\n" | 
|  | "  movl %0, %2\n" | 
|  | "  shrl $16, %0\n" | 
|  | "  addw %w2, %w0\n" | 
|  | "  adcl $0, %0\n" | 
|  | "  notl %0\n" | 
|  | "2:" | 
|  | /* Since the input registers which are loaded with iph and ipl | 
|  | are modified, we must also specify them as outputs, or gcc | 
|  | will assume they contain their original values. */ | 
|  | : "=r" (sum), "=r" (iph), "=r" (ihl) | 
|  | : "1" (iph), "2" (ihl) | 
|  | : "memory"); | 
|  | return (__force __sum16)sum; | 
|  | } | 
|  |  | 
|  | #ifdef CONFIG_X86_32 | 
|  | # include "checksum_32.h" | 
|  | #else | 
|  | # include "checksum_64.h" | 
|  | #endif | 
|  |  | 
|  | #endif |