uboot/net/checksum.c
<<
>>
Prefs
   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
  11#include <common.h>
  12#include <net.h>
  13
  14unsigned compute_ip_checksum(const void *vptr, unsigned nbytes)
  15{
  16        int sum, oddbyte;
  17        const unsigned short *ptr = vptr;
  18
  19        sum = 0;
  20        while (nbytes > 1) {
  21                sum += *ptr++;
  22                nbytes -= 2;
  23        }
  24        if (nbytes == 1) {
  25                oddbyte = 0;
  26                ((u8 *)&oddbyte)[0] = *(u8 *)ptr;
  27                ((u8 *)&oddbyte)[1] = 0;
  28                sum += oddbyte;
  29        }
  30        sum = (sum >> 16) + (sum & 0xffff);
  31        sum += (sum >> 16);
  32        sum = ~sum & 0xffff;
  33
  34        return sum;
  35}
  36
  37unsigned add_ip_checksums(unsigned offset, unsigned sum, unsigned new)
  38{
  39        unsigned long checksum;
  40
  41        sum = ~sum & 0xffff;
  42        new = ~new & 0xffff;
  43        if (offset & 1) {
  44                /*
  45                 * byte-swap the sum if it came from an odd offset; since the
  46                 * computation is endian independant this works.
  47                 */
  48                new = ((new >> 8) & 0xff) | ((new << 8) & 0xff00);
  49        }
  50        checksum = sum + new;
  51        if (checksum > 0xffff)
  52                checksum -= 0xffff;
  53
  54        return (~checksum) & 0xffff;
  55}
  56
  57int ip_checksum_ok(const void *addr, unsigned nbytes)
  58{
  59        return !(compute_ip_checksum(addr, nbytes) & 0xfffe);
  60}
  61