Back to home page

OSCL-LXR

 
 

    


0001 /* SPDX-License-Identifier: GPL-2.0 */
0002 #ifndef _ASM_X86_CHECKSUM_64_H
0003 #define _ASM_X86_CHECKSUM_64_H
0004 
0005 /*
0006  * Checksums for x86-64
0007  * Copyright 2002 by Andi Kleen, SuSE Labs
0008  * with some code from asm-x86/checksum.h
0009  */
0010 
0011 #include <linux/compiler.h>
0012 #include <linux/uaccess.h>
0013 #include <asm/byteorder.h>
0014 
0015 /**
0016  * csum_fold - Fold and invert a 32bit checksum.
0017  * sum: 32bit unfolded sum
0018  *
0019  * Fold a 32bit running checksum to 16bit and invert it. This is usually
0020  * the last step before putting a checksum into a packet.
0021  * Make sure not to mix with 64bit checksums.
0022  */
0023 static inline __sum16 csum_fold(__wsum sum)
0024 {
0025     asm("  addl %1,%0\n"
0026         "  adcl $0xffff,%0"
0027         : "=r" (sum)
0028         : "r" ((__force u32)sum << 16),
0029           "0" ((__force u32)sum & 0xffff0000));
0030     return (__force __sum16)(~(__force u32)sum >> 16);
0031 }
0032 
0033 /*
0034  *  This is a version of ip_compute_csum() optimized for IP headers,
0035  *  which always checksum on 4 octet boundaries.
0036  *
0037  *  By Jorge Cwik <jorge@laser.satlink.net>, adapted for linux by
0038  *  Arnt Gulbrandsen.
0039  */
0040 
0041 /**
0042  * ip_fast_csum - Compute the IPv4 header checksum efficiently.
0043  * iph: ipv4 header
0044  * ihl: length of header / 4
0045  */
0046 static inline __sum16 ip_fast_csum(const void *iph, unsigned int ihl)
0047 {
0048     unsigned int sum;
0049 
0050     asm("  movl (%1), %0\n"
0051         "  subl $4, %2\n"
0052         "  jbe 2f\n"
0053         "  addl 4(%1), %0\n"
0054         "  adcl 8(%1), %0\n"
0055         "  adcl 12(%1), %0\n"
0056         "1: adcl 16(%1), %0\n"
0057         "  lea 4(%1), %1\n"
0058         "  decl %2\n"
0059         "  jne  1b\n"
0060         "  adcl $0, %0\n"
0061         "  movl %0, %2\n"
0062         "  shrl $16, %0\n"
0063         "  addw %w2, %w0\n"
0064         "  adcl $0, %0\n"
0065         "  notl %0\n"
0066         "2:"
0067     /* Since the input registers which are loaded with iph and ihl
0068        are modified, we must also specify them as outputs, or gcc
0069        will assume they contain their original values. */
0070         : "=r" (sum), "=r" (iph), "=r" (ihl)
0071         : "1" (iph), "2" (ihl)
0072         : "memory");
0073     return (__force __sum16)sum;
0074 }
0075 
0076 /**
0077  * csum_tcpup_nofold - Compute an IPv4 pseudo header checksum.
0078  * @saddr: source address
0079  * @daddr: destination address
0080  * @len: length of packet
0081  * @proto: ip protocol of packet
0082  * @sum: initial sum to be added in (32bit unfolded)
0083  *
0084  * Returns the pseudo header checksum the input data. Result is
0085  * 32bit unfolded.
0086  */
0087 static inline __wsum
0088 csum_tcpudp_nofold(__be32 saddr, __be32 daddr, __u32 len,
0089            __u8 proto, __wsum sum)
0090 {
0091     asm("  addl %1, %0\n"
0092         "  adcl %2, %0\n"
0093         "  adcl %3, %0\n"
0094         "  adcl $0, %0\n"
0095         : "=r" (sum)
0096         : "g" (daddr), "g" (saddr),
0097           "g" ((len + proto)<<8), "0" (sum));
0098     return sum;
0099 }
0100 
0101 
0102 /**
0103  * csum_tcpup_magic - Compute an IPv4 pseudo header checksum.
0104  * @saddr: source address
0105  * @daddr: destination address
0106  * @len: length of packet
0107  * @proto: ip protocol of packet
0108  * @sum: initial sum to be added in (32bit unfolded)
0109  *
0110  * Returns the 16bit pseudo header checksum the input data already
0111  * complemented and ready to be filled in.
0112  */
0113 static inline __sum16 csum_tcpudp_magic(__be32 saddr, __be32 daddr,
0114                     __u32 len, __u8 proto,
0115                     __wsum sum)
0116 {
0117     return csum_fold(csum_tcpudp_nofold(saddr, daddr, len, proto, sum));
0118 }
0119 
0120 /**
0121  * csum_partial - Compute an internet checksum.
0122  * @buff: buffer to be checksummed
0123  * @len: length of buffer.
0124  * @sum: initial sum to be added in (32bit unfolded)
0125  *
0126  * Returns the 32bit unfolded internet checksum of the buffer.
0127  * Before filling it in it needs to be csum_fold()'ed.
0128  * buff should be aligned to a 64bit boundary if possible.
0129  */
0130 extern __wsum csum_partial(const void *buff, int len, __wsum sum);
0131 
0132 /* Do not call this directly. Use the wrappers below */
0133 extern __visible __wsum csum_partial_copy_generic(const void *src, void *dst, int len);
0134 
0135 extern __wsum csum_and_copy_from_user(const void __user *src, void *dst, int len);
0136 extern __wsum csum_and_copy_to_user(const void *src, void __user *dst, int len);
0137 extern __wsum csum_partial_copy_nocheck(const void *src, void *dst, int len);
0138 
0139 /**
0140  * ip_compute_csum - Compute an 16bit IP checksum.
0141  * @buff: buffer address.
0142  * @len: length of buffer.
0143  *
0144  * Returns the 16bit folded/inverted checksum of the passed buffer.
0145  * Ready to fill in.
0146  */
0147 extern __sum16 ip_compute_csum(const void *buff, int len);
0148 
0149 /**
0150  * csum_ipv6_magic - Compute checksum of an IPv6 pseudo header.
0151  * @saddr: source address
0152  * @daddr: destination address
0153  * @len: length of packet
0154  * @proto: protocol of packet
0155  * @sum: initial sum (32bit unfolded) to be added in
0156  *
0157  * Computes an IPv6 pseudo header checksum. This sum is added the checksum
0158  * into UDP/TCP packets and contains some link layer information.
0159  * Returns the unfolded 32bit checksum.
0160  */
0161 
0162 struct in6_addr;
0163 
0164 #define _HAVE_ARCH_IPV6_CSUM 1
0165 extern __sum16
0166 csum_ipv6_magic(const struct in6_addr *saddr, const struct in6_addr *daddr,
0167         __u32 len, __u8 proto, __wsum sum);
0168 
0169 static inline unsigned add32_with_carry(unsigned a, unsigned b)
0170 {
0171     asm("addl %2,%0\n\t"
0172         "adcl $0,%0"
0173         : "=r" (a)
0174         : "0" (a), "rm" (b));
0175     return a;
0176 }
0177 
0178 #define HAVE_ARCH_CSUM_ADD
0179 static inline __wsum csum_add(__wsum csum, __wsum addend)
0180 {
0181     return (__force __wsum)add32_with_carry((__force unsigned)csum,
0182                         (__force unsigned)addend);
0183 }
0184 
0185 #endif /* _ASM_X86_CHECKSUM_64_H */