checksum.c 1.2 KB

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