Path: blob/master/arch/um/sys-i386/shared/sysdep/checksum.h
17705 views
/*1* Licensed under the GPL2*/34#ifndef __UM_SYSDEP_CHECKSUM_H5#define __UM_SYSDEP_CHECKSUM_H67#include "linux/in6.h"8#include "linux/string.h"910/*11* computes the checksum of a memory block at buff, length len,12* and adds in "sum" (32-bit)13*14* returns a 32-bit number suitable for feeding into itself15* or csum_tcpudp_magic16*17* this function must be called with even lengths, except18* for the last fragment, which may be odd19*20* it's best to have buff aligned on a 32-bit boundary21*/22__wsum csum_partial(const void *buff, int len, __wsum sum);2324/*25* Note: when you get a NULL pointer exception here this means someone26* passed in an incorrect kernel address to one of these functions.27*28* If you use these functions directly please don't forget the29* access_ok().30*/3132static __inline__33__wsum csum_partial_copy_nocheck(const void *src, void *dst,34int len, __wsum sum)35{36memcpy(dst, src, len);37return csum_partial(dst, len, sum);38}3940/*41* the same as csum_partial, but copies from src while it42* checksums, and handles user-space pointer exceptions correctly, when needed.43*44* here even more important to align src and dst on a 32-bit (or even45* better 64-bit) boundary46*/4748static __inline__49__wsum csum_partial_copy_from_user(const void __user *src, void *dst,50int len, __wsum sum, int *err_ptr)51{52if (copy_from_user(dst, src, len)) {53*err_ptr = -EFAULT;54return (__force __wsum)-1;55}5657return csum_partial(dst, len, sum);58}5960/*61* This is a version of ip_compute_csum() optimized for IP headers,62* which always checksum on 4 octet boundaries.63*64* By Jorge Cwik <[email protected]>, adapted for linux by65* Arnt Gulbrandsen.66*/67static inline __sum16 ip_fast_csum(const void *iph, unsigned int ihl)68{69unsigned int sum;7071__asm__ __volatile__(72"movl (%1), %0 ;\n"73"subl $4, %2 ;\n"74"jbe 2f ;\n"75"addl 4(%1), %0 ;\n"76"adcl 8(%1), %0 ;\n"77"adcl 12(%1), %0 ;\n"78"1: adcl 16(%1), %0 ;\n"79"lea 4(%1), %1 ;\n"80"decl %2 ;\n"81"jne 1b ;\n"82"adcl $0, %0 ;\n"83"movl %0, %2 ;\n"84"shrl $16, %0 ;\n"85"addw %w2, %w0 ;\n"86"adcl $0, %0 ;\n"87"notl %0 ;\n"88"2: ;\n"89/* Since the input registers which are loaded with iph and ipl90are modified, we must also specify them as outputs, or gcc91will assume they contain their original values. */92: "=r" (sum), "=r" (iph), "=r" (ihl)93: "1" (iph), "2" (ihl)94: "memory");95return (__force __sum16)sum;96}9798/*99* Fold a partial checksum100*/101102static inline __sum16 csum_fold(__wsum sum)103{104__asm__(105"addl %1, %0 ;\n"106"adcl $0xffff, %0 ;\n"107: "=r" (sum)108: "r" ((__force u32)sum << 16),109"0" ((__force u32)sum & 0xffff0000)110);111return (__force __sum16)(~(__force u32)sum >> 16);112}113114static inline __wsum csum_tcpudp_nofold(__be32 saddr, __be32 daddr,115unsigned short len,116unsigned short proto,117__wsum sum)118{119__asm__(120"addl %1, %0 ;\n"121"adcl %2, %0 ;\n"122"adcl %3, %0 ;\n"123"adcl $0, %0 ;\n"124: "=r" (sum)125: "g" (daddr), "g"(saddr), "g"((len + proto) << 8), "0"(sum));126return sum;127}128129/*130* computes the checksum of the TCP/UDP pseudo-header131* returns a 16-bit checksum, already complemented132*/133static inline __sum16 csum_tcpudp_magic(__be32 saddr, __be32 daddr,134unsigned short len,135unsigned short proto,136__wsum sum)137{138return csum_fold(csum_tcpudp_nofold(saddr,daddr,len,proto,sum));139}140141/*142* this routine is used for miscellaneous IP-like checksums, mainly143* in icmp.c144*/145146static inline __sum16 ip_compute_csum(const void *buff, int len)147{148return csum_fold (csum_partial(buff, len, 0));149}150151#define _HAVE_ARCH_IPV6_CSUM152static __inline__ __sum16 csum_ipv6_magic(const struct in6_addr *saddr,153const struct in6_addr *daddr,154__u32 len, unsigned short proto,155__wsum sum)156{157__asm__(158"addl 0(%1), %0 ;\n"159"adcl 4(%1), %0 ;\n"160"adcl 8(%1), %0 ;\n"161"adcl 12(%1), %0 ;\n"162"adcl 0(%2), %0 ;\n"163"adcl 4(%2), %0 ;\n"164"adcl 8(%2), %0 ;\n"165"adcl 12(%2), %0 ;\n"166"adcl %3, %0 ;\n"167"adcl %4, %0 ;\n"168"adcl $0, %0 ;\n"169: "=&r" (sum)170: "r" (saddr), "r" (daddr),171"r"(htonl(len)), "r"(htonl(proto)), "0"(sum));172173return csum_fold(sum);174}175176/*177* Copy and checksum to user178*/179#define HAVE_CSUM_COPY_USER180static __inline__ __wsum csum_and_copy_to_user(const void *src,181void __user *dst,182int len, __wsum sum, int *err_ptr)183{184if (access_ok(VERIFY_WRITE, dst, len)) {185if (copy_to_user(dst, src, len)) {186*err_ptr = -EFAULT;187return (__force __wsum)-1;188}189190return csum_partial(src, len, sum);191}192193if (len)194*err_ptr = -EFAULT;195196return (__force __wsum)-1; /* invalid checksum */197}198199#endif200201202203