Commit 9b0e35cb4889eb04a7ea5dd648d73df0bf37cc68

Authored by Simon Glass
1 parent 5da38086bd

net: Add a separate file for IP checksumming

Move the checksum code out into its own file so it can be used elsewhere.
Also use a new version which supports a length which is not a multiple of
2 and add a new function to add two checksums.

Signed-off-by: Simon Glass <sjg@chromium.org>

Showing 3 changed files with 91 additions and 0 deletions Side-by-side Diff

... ... @@ -482,6 +482,36 @@
482 482 extern void net_set_udp_header(uchar *pkt, IPaddr_t dest, int dport,
483 483 int sport, int len);
484 484  
  485 +/**
  486 + * compute_ip_checksum() - Compute IP checksum
  487 + *
  488 + * @addr: Address to check (must be 16-bit aligned)
  489 + * @nbytes: Number of bytes to check (normally a multiple of 2)
  490 + * @return 16-bit IP checksum
  491 + */
  492 +unsigned compute_ip_checksum(const void *addr, unsigned nbytes);
  493 +
  494 +/**
  495 + * add_ip_checksums() - add two IP checksums
  496 + *
  497 + * @offset: Offset of first sum (if odd we do a byte-swap)
  498 + * @sum: First checksum
  499 + * @new_sum: New checksum to add
  500 + * @return updated 16-bit IP checksum
  501 + */
  502 +unsigned add_ip_checksums(unsigned offset, unsigned sum, unsigned new_sum);
  503 +
  504 +/**
  505 + * ip_checksum_ok() - check if a checksum is correct
  506 + *
  507 + * This works by making sure the checksum sums to 0
  508 + *
  509 + * @addr: Address to check (must be 16-bit aligned)
  510 + * @nbytes: Number of bytes to check (normally a multiple of 2)
  511 + * @return true if the checksum matches, false if not
  512 + */
  513 +int ip_checksum_ok(const void *addr, unsigned nbytes);
  514 +
485 515 /* Checksum */
486 516 extern int NetCksumOk(uchar *, int); /* Return true if cksum OK */
487 517 extern uint NetCksum(uchar *, int); /* Calculate the checksum */
... ... @@ -7,6 +7,7 @@
7 7  
8 8 #ccflags-y += -DDEBUG
9 9  
  10 +obj-y += checksum.o
10 11 obj-$(CONFIG_CMD_NET) += arp.o
11 12 obj-$(CONFIG_CMD_NET) += bootp.o
12 13 obj-$(CONFIG_CMD_CDP) += cdp.o
  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 +
  14 +unsigned 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 +
  37 +unsigned 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 +
  57 +int ip_checksum_ok(const void *addr, unsigned nbytes)
  58 +{
  59 + return !(compute_ip_checksum(addr, nbytes) & 0xfffe);
  60 +}