/* SPDX-License-Identifier: GPL-2.0 */1#ifndef _ASM_X86_CHECKSUM_64_H2#define _ASM_X86_CHECKSUM_64_H34/*5* Checksums for x86-646* Copyright 2002 by Andi Kleen, SuSE Labs7* with some code from asm-x86/checksum.h8*/910#include <linux/compiler.h>11#include <asm/byteorder.h>1213/**14* csum_fold - Fold and invert a 32bit checksum.15* sum: 32bit unfolded sum16*17* Fold a 32bit running checksum to 16bit and invert it. This is usually18* the last step before putting a checksum into a packet.19* Make sure not to mix with 64bit checksums.20*/21static inline __sum16 csum_fold(__wsum sum)22{23asm(" addl %1,%0\n"24" adcl $0xffff,%0"25: "=r" (sum)26: "r" ((__force u32)sum << 16),27"0" ((__force u32)sum & 0xffff0000));28return (__force __sum16)(~(__force u32)sum >> 16);29}3031/*32* This is a version of ip_compute_csum() optimized for IP headers,33* which always checksum on 4 octet boundaries.34*35* By Jorge Cwik <[email protected]>, adapted for linux by36* Arnt Gulbrandsen.37*/3839/**40* ip_fast_csum - Compute the IPv4 header checksum efficiently.41* iph: ipv4 header42* ihl: length of header / 443*/44static inline __sum16 ip_fast_csum(const void *iph, unsigned int ihl)45{46unsigned int sum;4748asm(" movl (%1), %0\n"49" subl $4, %2\n"50" jbe 2f\n"51" addl 4(%1), %0\n"52" adcl 8(%1), %0\n"53" adcl 12(%1), %0\n"54"1: adcl 16(%1), %0\n"55" lea 4(%1), %1\n"56" decl %2\n"57" jne 1b\n"58" adcl $0, %0\n"59" movl %0, %2\n"60" shrl $16, %0\n"61" addw %w2, %w0\n"62" adcl $0, %0\n"63" notl %0\n"64"2:"65/* Since the input registers which are loaded with iph and ihl66are modified, we must also specify them as outputs, or gcc67will assume they contain their original values. */68: "=r" (sum), "=r" (iph), "=r" (ihl)69: "1" (iph), "2" (ihl)70: "memory");71return (__force __sum16)sum;72}7374/**75* csum_tcpup_nofold - Compute an IPv4 pseudo header checksum.76* @saddr: source address77* @daddr: destination address78* @len: length of packet79* @proto: ip protocol of packet80* @sum: initial sum to be added in (32bit unfolded)81*82* Returns the pseudo header checksum the input data. Result is83* 32bit unfolded.84*/85static inline __wsum86csum_tcpudp_nofold(__be32 saddr, __be32 daddr, __u32 len,87__u8 proto, __wsum sum)88{89asm(" addl %1, %0\n"90" adcl %2, %0\n"91" adcl %3, %0\n"92" adcl $0, %0\n"93: "=r" (sum)94: "g" (daddr), "g" (saddr),95"g" ((len + proto)<<8), "0" (sum));96return sum;97}9899100/**101* csum_tcpup_magic - Compute an IPv4 pseudo header checksum.102* @saddr: source address103* @daddr: destination address104* @len: length of packet105* @proto: ip protocol of packet106* @sum: initial sum to be added in (32bit unfolded)107*108* Returns the 16bit pseudo header checksum the input data already109* complemented and ready to be filled in.110*/111static inline __sum16 csum_tcpudp_magic(__be32 saddr, __be32 daddr,112__u32 len, __u8 proto,113__wsum sum)114{115return csum_fold(csum_tcpudp_nofold(saddr, daddr, len, proto, sum));116}117118/**119* csum_partial - Compute an internet checksum.120* @buff: buffer to be checksummed121* @len: length of buffer.122* @sum: initial sum to be added in (32bit unfolded)123*124* Returns the 32bit unfolded internet checksum of the buffer.125* Before filling it in it needs to be csum_fold()'ed.126* buff should be aligned to a 64bit boundary if possible.127*/128extern __wsum csum_partial(const void *buff, int len, __wsum sum);129130/* Do not call this directly. Use the wrappers below */131extern __visible __wsum csum_partial_copy_generic(const void *src, void *dst, int len);132133extern __wsum csum_and_copy_from_user(const void __user *src, void *dst, int len);134extern __wsum csum_and_copy_to_user(const void *src, void __user *dst, int len);135extern __wsum csum_partial_copy_nocheck(const void *src, void *dst, int len);136137/**138* ip_compute_csum - Compute an 16bit IP checksum.139* @buff: buffer address.140* @len: length of buffer.141*142* Returns the 16bit folded/inverted checksum of the passed buffer.143* Ready to fill in.144*/145extern __sum16 ip_compute_csum(const void *buff, int len);146147/**148* csum_ipv6_magic - Compute checksum of an IPv6 pseudo header.149* @saddr: source address150* @daddr: destination address151* @len: length of packet152* @proto: protocol of packet153* @sum: initial sum (32bit unfolded) to be added in154*155* Computes an IPv6 pseudo header checksum. This sum is added the checksum156* into UDP/TCP packets and contains some link layer information.157* Returns the unfolded 32bit checksum.158*/159160struct in6_addr;161162#define _HAVE_ARCH_IPV6_CSUM 1163extern __sum16164csum_ipv6_magic(const struct in6_addr *saddr, const struct in6_addr *daddr,165__u32 len, __u8 proto, __wsum sum);166167static inline unsigned add32_with_carry(unsigned a, unsigned b)168{169asm("addl %2,%0\n\t"170"adcl $0,%0"171: "=r" (a)172: "0" (a), "rm" (b));173return a;174}175176#define HAVE_ARCH_CSUM_ADD177static inline __wsum csum_add(__wsum csum, __wsum addend)178{179return (__force __wsum)add32_with_carry((__force unsigned)csum,180(__force unsigned)addend);181}182183#endif /* _ASM_X86_CHECKSUM_64_H */184185186