Path: blob/master/arch/mips/include/asm/checksum.h
17359 views
/*1* This file is subject to the terms and conditions of the GNU General Public2* License. See the file "COPYING" in the main directory of this archive3* for more details.4*5* Copyright (C) 1995, 96, 97, 98, 99, 2001 by Ralf Baechle6* Copyright (C) 1999 Silicon Graphics, Inc.7* Copyright (C) 2001 Thiemo Seufer.8* Copyright (C) 2002 Maciej W. Rozycki9*/10#ifndef _ASM_CHECKSUM_H11#define _ASM_CHECKSUM_H1213#include <linux/in6.h>1415#include <asm/uaccess.h>1617/*18* computes the checksum of a memory block at buff, length len,19* and adds in "sum" (32-bit)20*21* returns a 32-bit number suitable for feeding into itself22* or csum_tcpudp_magic23*24* this function must be called with even lengths, except25* for the last fragment, which may be odd26*27* it's best to have buff aligned on a 32-bit boundary28*/29__wsum csum_partial(const void *buff, int len, __wsum sum);3031__wsum __csum_partial_copy_user(const void *src, void *dst,32int len, __wsum sum, int *err_ptr);3334/*35* this is a new version of the above that records errors it finds in *errp,36* but continues and zeros the rest of the buffer.37*/38static inline39__wsum csum_partial_copy_from_user(const void __user *src, void *dst, int len,40__wsum sum, int *err_ptr)41{42might_fault();43return __csum_partial_copy_user((__force void *)src, dst,44len, sum, err_ptr);45}4647/*48* Copy and checksum to user49*/50#define HAVE_CSUM_COPY_USER51static inline52__wsum csum_and_copy_to_user(const void *src, void __user *dst, int len,53__wsum sum, int *err_ptr)54{55might_fault();56if (access_ok(VERIFY_WRITE, dst, len))57return __csum_partial_copy_user(src, (__force void *)dst,58len, sum, err_ptr);59if (len)60*err_ptr = -EFAULT;6162return (__force __wsum)-1; /* invalid checksum */63}6465/*66* the same as csum_partial, but copies from user space (but on MIPS67* we have just one address space, so this is identical to the above)68*/69__wsum csum_partial_copy_nocheck(const void *src, void *dst,70int len, __wsum sum);7172/*73* Fold a partial checksum without adding pseudo headers74*/75static inline __sum16 csum_fold(__wsum sum)76{77__asm__(78" .set push # csum_fold\n"79" .set noat \n"80" sll $1, %0, 16 \n"81" addu %0, $1 \n"82" sltu $1, %0, $1 \n"83" srl %0, %0, 16 \n"84" addu %0, $1 \n"85" xori %0, 0xffff \n"86" .set pop"87: "=r" (sum)88: "0" (sum));8990return (__force __sum16)sum;91}9293/*94* This is a version of ip_compute_csum() optimized for IP headers,95* which always checksum on 4 octet boundaries.96*97* By Jorge Cwik <[email protected]>, adapted for linux by98* Arnt Gulbrandsen.99*/100static inline __sum16 ip_fast_csum(const void *iph, unsigned int ihl)101{102const unsigned int *word = iph;103const unsigned int *stop = word + ihl;104unsigned int csum;105int carry;106107csum = word[0];108csum += word[1];109carry = (csum < word[1]);110csum += carry;111112csum += word[2];113carry = (csum < word[2]);114csum += carry;115116csum += word[3];117carry = (csum < word[3]);118csum += carry;119120word += 4;121do {122csum += *word;123carry = (csum < *word);124csum += carry;125word++;126} while (word != stop);127128return csum_fold(csum);129}130131static inline __wsum csum_tcpudp_nofold(__be32 saddr,132__be32 daddr, unsigned short len, unsigned short proto,133__wsum sum)134{135__asm__(136" .set push # csum_tcpudp_nofold\n"137" .set noat \n"138#ifdef CONFIG_32BIT139" addu %0, %2 \n"140" sltu $1, %0, %2 \n"141" addu %0, $1 \n"142143" addu %0, %3 \n"144" sltu $1, %0, %3 \n"145" addu %0, $1 \n"146147" addu %0, %4 \n"148" sltu $1, %0, %4 \n"149" addu %0, $1 \n"150#endif151#ifdef CONFIG_64BIT152" daddu %0, %2 \n"153" daddu %0, %3 \n"154" daddu %0, %4 \n"155" dsll32 $1, %0, 0 \n"156" daddu %0, $1 \n"157" dsra32 %0, %0, 0 \n"158#endif159" .set pop"160: "=r" (sum)161: "0" ((__force unsigned long)daddr),162"r" ((__force unsigned long)saddr),163#ifdef __MIPSEL__164"r" ((proto + len) << 8),165#else166"r" (proto + len),167#endif168"r" ((__force unsigned long)sum));169170return sum;171}172173/*174* computes the checksum of the TCP/UDP pseudo-header175* returns a 16-bit checksum, already complemented176*/177static inline __sum16 csum_tcpudp_magic(__be32 saddr, __be32 daddr,178unsigned short len,179unsigned short proto,180__wsum sum)181{182return csum_fold(csum_tcpudp_nofold(saddr, daddr, len, proto, sum));183}184185/*186* this routine is used for miscellaneous IP-like checksums, mainly187* in icmp.c188*/189static inline __sum16 ip_compute_csum(const void *buff, int len)190{191return csum_fold(csum_partial(buff, len, 0));192}193194#define _HAVE_ARCH_IPV6_CSUM195static __inline__ __sum16 csum_ipv6_magic(const struct in6_addr *saddr,196const struct in6_addr *daddr,197__u32 len, unsigned short proto,198__wsum sum)199{200__asm__(201" .set push # csum_ipv6_magic\n"202" .set noreorder \n"203" .set noat \n"204" addu %0, %5 # proto (long in network byte order)\n"205" sltu $1, %0, %5 \n"206" addu %0, $1 \n"207208" addu %0, %6 # csum\n"209" sltu $1, %0, %6 \n"210" lw %1, 0(%2) # four words source address\n"211" addu %0, $1 \n"212" addu %0, %1 \n"213" sltu $1, %0, %1 \n"214215" lw %1, 4(%2) \n"216" addu %0, $1 \n"217" addu %0, %1 \n"218" sltu $1, %0, %1 \n"219220" lw %1, 8(%2) \n"221" addu %0, $1 \n"222" addu %0, %1 \n"223" sltu $1, %0, %1 \n"224225" lw %1, 12(%2) \n"226" addu %0, $1 \n"227" addu %0, %1 \n"228" sltu $1, %0, %1 \n"229230" lw %1, 0(%3) \n"231" addu %0, $1 \n"232" addu %0, %1 \n"233" sltu $1, %0, %1 \n"234235" lw %1, 4(%3) \n"236" addu %0, $1 \n"237" addu %0, %1 \n"238" sltu $1, %0, %1 \n"239240" lw %1, 8(%3) \n"241" addu %0, $1 \n"242" addu %0, %1 \n"243" sltu $1, %0, %1 \n"244245" lw %1, 12(%3) \n"246" addu %0, $1 \n"247" addu %0, %1 \n"248" sltu $1, %0, %1 \n"249250" addu %0, $1 # Add final carry\n"251" .set pop"252: "=r" (sum), "=r" (proto)253: "r" (saddr), "r" (daddr),254"0" (htonl(len)), "1" (htonl(proto)), "r" (sum));255256return csum_fold(sum);257}258259#endif /* _ASM_CHECKSUM_H */260261262