csum_partial_copy.c
上传用户:lgb322
上传日期:2013-02-24
资源大小:30529k
文件大小:3k
源码类别:

嵌入式Linux

开发平台:

Unix_Linux

  1. /*
  2.  * Network Checksum & Copy routine
  3.  *
  4.  * Copyright (C) 1999 Hewlett-Packard Co
  5.  * Copyright (C) 1999 Stephane Eranian <eranian@hpl.hp.com>
  6.  *
  7.  * Most of the code has been imported from Linux/Alpha
  8.  */
  9. #include <linux/types.h>
  10. #include <linux/string.h>
  11. #include <asm/uaccess.h>
  12. /*
  13.  * XXX Fixme: those 2 inlines are meant for debugging and will go away
  14.  */
  15. static inline unsigned
  16. short from64to16(unsigned long x)
  17. {
  18. /* add up 32-bit words for 33 bits */
  19. x = (x & 0xffffffff) + (x >> 32);
  20. /* add up 16-bit and 17-bit words for 17+c bits */
  21. x = (x & 0xffff) + (x >> 16);
  22. /* add up 16-bit and 2-bit for 16+c bit */
  23. x = (x & 0xffff) + (x >> 16);
  24. /* add up carry.. */
  25. x = (x & 0xffff) + (x >> 16);
  26. return x;
  27. }
  28. static inline
  29. unsigned long do_csum_c(const unsigned char * buff, int len, unsigned int psum)
  30. {
  31. int odd, count;
  32. unsigned long result = (unsigned long)psum;
  33. if (len <= 0)
  34. goto out;
  35. odd = 1 & (unsigned long) buff;
  36. if (odd) {
  37. result = *buff << 8;
  38. len--;
  39. buff++;
  40. }
  41. count = len >> 1; /* nr of 16-bit words.. */
  42. if (count) {
  43. if (2 & (unsigned long) buff) {
  44. result += *(unsigned short *) buff;
  45. count--;
  46. len -= 2;
  47. buff += 2;
  48. }
  49. count >>= 1; /* nr of 32-bit words.. */
  50. if (count) {
  51. if (4 & (unsigned long) buff) {
  52. result += *(unsigned int *) buff;
  53. count--;
  54. len -= 4;
  55. buff += 4;
  56. }
  57. count >>= 1; /* nr of 64-bit words.. */
  58. if (count) {
  59. unsigned long carry = 0;
  60. do {
  61. unsigned long w = *(unsigned long *) buff;
  62. count--;
  63. buff += 8;
  64. result += carry;
  65. result += w;
  66. carry = (w > result);
  67. } while (count);
  68. result += carry;
  69. result = (result & 0xffffffff) + (result >> 32);
  70. }
  71. if (len & 4) {
  72. result += *(unsigned int *) buff;
  73. buff += 4;
  74. }
  75. }
  76. if (len & 2) {
  77. result += *(unsigned short *) buff;
  78. buff += 2;
  79. }
  80. }
  81. if (len & 1)
  82. result += *buff;
  83. result = from64to16(result);
  84. if (odd)
  85. result = ((result >> 8) & 0xff) | ((result & 0xff) << 8);
  86. out:
  87. return result;
  88. }
  89. /*
  90.  * XXX Fixme
  91.  *
  92.  * This is very ugly but temporary. THIS NEEDS SERIOUS ENHANCEMENTS.
  93.  * But it's very tricky to get right even in C.
  94.  */
  95. extern unsigned long do_csum(const unsigned char *, long);
  96. static unsigned int
  97. do_csum_partial_copy_from_user (const char *src, char *dst, int len,
  98. unsigned int psum, int *errp)
  99. {
  100. unsigned long result;
  101. /* XXX Fixme
  102.  * for now we separate the copy from checksum for obvious
  103.  * alignment difficulties. Look at the Alpha code and you'll be
  104.  * scared.
  105.  */
  106. if (__copy_from_user(dst, src, len) != 0 && errp)
  107. *errp = -EFAULT;
  108. result = do_csum(dst, len);
  109. /* add in old sum, and carry.. */
  110. result += psum;
  111. /* 32+c bits -> 32 bits */
  112. result = (result & 0xffffffff) + (result >> 32);
  113. return result;
  114. }
  115. unsigned int
  116. csum_partial_copy_from_user(const char *src, char *dst, int len,
  117.     unsigned int sum, int *errp)
  118. {
  119. if (!access_ok(src, len, VERIFY_READ)) {
  120. *errp = -EFAULT;
  121. memset(dst, 0, len);
  122. return sum;
  123. }
  124. return do_csum_partial_copy_from_user(src, dst, len, sum, errp);
  125. }
  126. unsigned int
  127. csum_partial_copy_nocheck(const char *src, char *dst, int len, unsigned int sum)
  128. {
  129. return do_csum_partial_copy_from_user(src, dst, len, sum, NULL);
  130. }
  131. unsigned int
  132. csum_partial_copy (const char *src, char *dst, int len, unsigned int sum)
  133. {
  134. unsigned int ret;
  135. int error = 0;
  136. ret = do_csum_partial_copy_from_user(src, dst, len, sum, &error);
  137. if (error)
  138. printk("csum_partial_copy_old(): tell mingo to convert me!n");
  139. return ret;
  140. }