checksum.h 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168
  1. /* $Id: checksum.h,v 1.19 2002/02/09 19:49:31 davem Exp $ */
  2. #ifndef __SPARC64_CHECKSUM_H
  3. #define __SPARC64_CHECKSUM_H
  4. /* checksum.h: IP/UDP/TCP checksum routines on the V9.
  5. *
  6. * Copyright(C) 1995 Linus Torvalds
  7. * Copyright(C) 1995 Miguel de Icaza
  8. * Copyright(C) 1996 David S. Miller
  9. * Copyright(C) 1996 Eddie C. Dost
  10. * Copyright(C) 1997 Jakub Jelinek
  11. *
  12. * derived from:
  13. * Alpha checksum c-code
  14. * ix86 inline assembly
  15. * RFC1071 Computing the Internet Checksum
  16. */
  17. #include <linux/in6.h>
  18. #include <asm/uaccess.h>
  19. /* computes the checksum of a memory block at buff, length len,
  20. * and adds in "sum" (32-bit)
  21. *
  22. * returns a 32-bit number suitable for feeding into itself
  23. * or csum_tcpudp_magic
  24. *
  25. * this function must be called with even lengths, except
  26. * for the last fragment, which may be odd
  27. *
  28. * it's best to have buff aligned on a 32-bit boundary
  29. */
  30. extern __wsum csum_partial(const void * buff, int len, __wsum sum);
  31. /* the same as csum_partial, but copies from user space while it
  32. * checksums
  33. *
  34. * here even more important to align src and dst on a 32-bit (or even
  35. * better 64-bit) boundary
  36. */
  37. extern __wsum csum_partial_copy_nocheck(const void *src, void *dst,
  38. int len, __wsum sum);
  39. extern long __csum_partial_copy_from_user(const void __user *src,
  40. void *dst, int len,
  41. __wsum sum);
  42. static inline __wsum
  43. csum_partial_copy_from_user(const void __user *src,
  44. void *dst, int len,
  45. __wsum sum, int *err)
  46. {
  47. long ret = __csum_partial_copy_from_user(src, dst, len, sum);
  48. if (ret < 0)
  49. *err = -EFAULT;
  50. return (__force __wsum) ret;
  51. }
  52. /*
  53. * Copy and checksum to user
  54. */
  55. #define HAVE_CSUM_COPY_USER
  56. extern long __csum_partial_copy_to_user(const void *src,
  57. void __user *dst, int len,
  58. __wsum sum);
  59. static inline __wsum
  60. csum_and_copy_to_user(const void *src,
  61. void __user *dst, int len,
  62. __wsum sum, int *err)
  63. {
  64. long ret = __csum_partial_copy_to_user(src, dst, len, sum);
  65. if (ret < 0)
  66. *err = -EFAULT;
  67. return (__force __wsum) ret;
  68. }
  69. /* ihl is always 5 or greater, almost always is 5, and iph is word aligned
  70. * the majority of the time.
  71. */
  72. extern __sum16 ip_fast_csum(const void *iph, unsigned int ihl);
  73. /* Fold a partial checksum without adding pseudo headers. */
  74. static inline __sum16 csum_fold(__wsum sum)
  75. {
  76. unsigned int tmp;
  77. __asm__ __volatile__(
  78. " addcc %0, %1, %1\n"
  79. " srl %1, 16, %1\n"
  80. " addc %1, %%g0, %1\n"
  81. " xnor %%g0, %1, %0\n"
  82. : "=&r" (sum), "=r" (tmp)
  83. : "0" (sum), "1" ((__force u32)sum<<16)
  84. : "cc");
  85. return (__force __sum16)sum;
  86. }
  87. static inline __wsum csum_tcpudp_nofold(__be32 saddr, __be32 daddr,
  88. unsigned int len,
  89. unsigned short proto,
  90. __wsum sum)
  91. {
  92. __asm__ __volatile__(
  93. " addcc %1, %0, %0\n"
  94. " addccc %2, %0, %0\n"
  95. " addccc %3, %0, %0\n"
  96. " addc %0, %%g0, %0\n"
  97. : "=r" (sum), "=r" (saddr)
  98. : "r" (daddr), "r" (proto + len), "0" (sum), "1" (saddr)
  99. : "cc");
  100. return sum;
  101. }
  102. /*
  103. * computes the checksum of the TCP/UDP pseudo-header
  104. * returns a 16-bit checksum, already complemented
  105. */
  106. static inline __sum16 csum_tcpudp_magic(__be32 saddr, __be32 daddr,
  107. unsigned short len,
  108. unsigned short proto,
  109. __wsum sum)
  110. {
  111. return csum_fold(csum_tcpudp_nofold(saddr,daddr,len,proto,sum));
  112. }
  113. #define _HAVE_ARCH_IPV6_CSUM
  114. static inline __sum16 csum_ipv6_magic(const struct in6_addr *saddr,
  115. const struct in6_addr *daddr,
  116. __u32 len, unsigned short proto,
  117. __wsum sum)
  118. {
  119. __asm__ __volatile__ (
  120. " addcc %3, %4, %%g7\n"
  121. " addccc %5, %%g7, %%g7\n"
  122. " lduw [%2 + 0x0c], %%g2\n"
  123. " lduw [%2 + 0x08], %%g3\n"
  124. " addccc %%g2, %%g7, %%g7\n"
  125. " lduw [%2 + 0x04], %%g2\n"
  126. " addccc %%g3, %%g7, %%g7\n"
  127. " lduw [%2 + 0x00], %%g3\n"
  128. " addccc %%g2, %%g7, %%g7\n"
  129. " lduw [%1 + 0x0c], %%g2\n"
  130. " addccc %%g3, %%g7, %%g7\n"
  131. " lduw [%1 + 0x08], %%g3\n"
  132. " addccc %%g2, %%g7, %%g7\n"
  133. " lduw [%1 + 0x04], %%g2\n"
  134. " addccc %%g3, %%g7, %%g7\n"
  135. " lduw [%1 + 0x00], %%g3\n"
  136. " addccc %%g2, %%g7, %%g7\n"
  137. " addccc %%g3, %%g7, %0\n"
  138. " addc 0, %0, %0\n"
  139. : "=&r" (sum)
  140. : "r" (saddr), "r" (daddr), "r"(htonl(len)),
  141. "r"(htonl(proto)), "r"(sum)
  142. : "g2", "g3", "g7", "cc");
  143. return csum_fold(sum);
  144. }
  145. /* this routine is used for miscellaneous IP-like checksums, mainly in icmp.c */
  146. static inline __sum16 ip_compute_csum(const void *buff, int len)
  147. {
  148. return csum_fold(csum_partial(buff, len, 0));
  149. }
  150. #endif /* !(__SPARC64_CHECKSUM_H) */