checksum.c 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125
  1. /*
  2. * Checksum routine for Internet Protocol family headers (C Version).
  3. *
  4. * Refer to "Computing the Internet Checksum" by R. Braden, D. Borman and
  5. * C. Partridge, Computer Communication Review, Vol. 19, No. 2, April 1989,
  6. * pp. 86-101, for additional details on computing this checksum.
  7. */
  8. #include <zebra.h>
  9. #include "checksum.h"
  10. int /* return checksum in low-order 16 bits */
  11. in_cksum(void *parg, int nbytes)
  12. {
  13. u_short *ptr = parg;
  14. register long sum; /* assumes long == 32 bits */
  15. u_short oddbyte;
  16. register u_short answer; /* assumes u_short == 16 bits */
  17. /*
  18. * Our algorithm is simple, using a 32-bit accumulator (sum),
  19. * we add sequential 16-bit words to it, and at the end, fold back
  20. * all the carry bits from the top 16 bits into the lower 16 bits.
  21. */
  22. sum = 0;
  23. while (nbytes > 1) {
  24. sum += *ptr++;
  25. nbytes -= 2;
  26. }
  27. /* mop up an odd byte, if necessary */
  28. if (nbytes == 1) {
  29. oddbyte = 0; /* make sure top half is zero */
  30. *((u_char *) &oddbyte) = *(u_char *)ptr; /* one byte only */
  31. sum += oddbyte;
  32. }
  33. /*
  34. * Add back carry outs from top 16 bits to low 16 bits.
  35. */
  36. sum = (sum >> 16) + (sum & 0xffff); /* add high-16 to low-16 */
  37. sum += (sum >> 16); /* add carry */
  38. answer = ~sum; /* ones-complement, then truncate to 16 bits */
  39. return(answer);
  40. }
  41. /* Fletcher Checksum -- Refer to RFC1008. */
  42. #define MODX 4102 /* 5802 should be fine */
  43. /* To be consistent, offset is 0-based index, rather than the 1-based
  44. index required in the specification ISO 8473, Annex C.1 */
  45. /* calling with offset == FLETCHER_CHECKSUM_VALIDATE will validate the checksum
  46. without modifying the buffer; a valid checksum returns 0 */
  47. u_int16_t
  48. fletcher_checksum(u_char * buffer, const size_t len, const uint16_t offset)
  49. {
  50. u_int8_t *p;
  51. int x, y, c0, c1;
  52. u_int16_t checksum;
  53. u_int16_t *csum;
  54. size_t partial_len, i, left = len;
  55. checksum = 0;
  56. if (offset != FLETCHER_CHECKSUM_VALIDATE)
  57. /* Zero the csum in the packet. */
  58. {
  59. assert (offset < (len - 1)); /* account for two bytes of checksum */
  60. csum = (u_int16_t *) (buffer + offset);
  61. *(csum) = 0;
  62. }
  63. p = buffer;
  64. c0 = 0;
  65. c1 = 0;
  66. while (left != 0)
  67. {
  68. partial_len = MIN(left, MODX);
  69. for (i = 0; i < partial_len; i++)
  70. {
  71. c0 = c0 + *(p++);
  72. c1 += c0;
  73. }
  74. c0 = c0 % 255;
  75. c1 = c1 % 255;
  76. left -= partial_len;
  77. }
  78. /* The cast is important, to ensure the mod is taken as a signed value. */
  79. x = (int)((len - offset - 1) * c0 - c1) % 255;
  80. if (x <= 0)
  81. x += 255;
  82. y = 510 - c0 - x;
  83. if (y > 255)
  84. y -= 255;
  85. if (offset == FLETCHER_CHECKSUM_VALIDATE)
  86. {
  87. checksum = (c1 << 8) + c0;
  88. }
  89. else
  90. {
  91. /*
  92. * Now we write this to the packet.
  93. * We could skip this step too, since the checksum returned would
  94. * be stored into the checksum field by the caller.
  95. */
  96. buffer[offset] = x;
  97. buffer[offset + 1] = y;
  98. /* Take care of the endian issue */
  99. checksum = htons((x << 8) | (y & 0xFF));
  100. }
  101. return checksum;
  102. }