checksum.c 1.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960
  1. /*
  2. * This file was originally taken from the FreeBSD project.
  3. *
  4. * Copyright (c) 2001 Charles Mott <cm@linktel.net>
  5. * Copyright (c) 2008 coresystems GmbH
  6. * All rights reserved.
  7. *
  8. * SPDX-License-Identifier: BSD-2-Clause
  9. */
  10. #include <common.h>
  11. #include <net.h>
  12. unsigned compute_ip_checksum(const void *vptr, unsigned nbytes)
  13. {
  14. int sum, oddbyte;
  15. const unsigned short *ptr = vptr;
  16. sum = 0;
  17. while (nbytes > 1) {
  18. sum += *ptr++;
  19. nbytes -= 2;
  20. }
  21. if (nbytes == 1) {
  22. oddbyte = 0;
  23. ((u8 *)&oddbyte)[0] = *(u8 *)ptr;
  24. ((u8 *)&oddbyte)[1] = 0;
  25. sum += oddbyte;
  26. }
  27. sum = (sum >> 16) + (sum & 0xffff);
  28. sum += (sum >> 16);
  29. sum = ~sum & 0xffff;
  30. return sum;
  31. }
  32. unsigned add_ip_checksums(unsigned offset, unsigned sum, unsigned new)
  33. {
  34. unsigned long checksum;
  35. sum = ~sum & 0xffff;
  36. new = ~new & 0xffff;
  37. if (offset & 1) {
  38. /*
  39. * byte-swap the sum if it came from an odd offset; since the
  40. * computation is endian independant this works.
  41. */
  42. new = ((new >> 8) & 0xff) | ((new << 8) & 0xff00);
  43. }
  44. checksum = sum + new;
  45. if (checksum > 0xffff)
  46. checksum -= 0xffff;
  47. return (~checksum) & 0xffff;
  48. }
  49. int ip_checksum_ok(const void *addr, unsigned nbytes)
  50. {
  51. return !(compute_ip_checksum(addr, nbytes) & 0xfffe);
  52. }