Quellcodebibliothek Statistik Leitseite products/sources/formale Sprachen/C/Linux/lib/   (Open Source Betriebssystem Version 6.17.9©)  Datei vom 24.10.2025 mit Größe 3 kB image not shown  

Quelle  checksum.c   Sprache: C

 
// SPDX-License-Identifier: GPL-2.0-or-later
/*
 *
 * INET An implementation of the TCP/IP protocol suite for the LINUX
 * operating system.  INET is implemented using the  BSD Socket
 * interface as the means of communication with the user level.
 *
 * IP/TCP/UDP checksumming routines
 *
 * Authors: Jorge Cwik, <jorge@laser.satlink.net>
 * Arnt Gulbrandsen, <agulbra@nvg.unit.no>
 * Tom May, <ftom@netcom.com>
 * Andreas Schwab, <schwab@issan.informatik.uni-dortmund.de>
 * Lots of code moved from tcp.c and ip.c; see those files
 * for more names.
 *
 * 03/02/96 Jes Sorensen, Andreas Schwab, Roman Hodek:
 * Fixed some nasty bugs, causing some horrible crashes.
 * A: At some points, the sum (%0) was used as
 * length-counter instead of the length counter
 * (%1). Thanks to Roman Hodek for pointing this out.
 * B: GCC seems to mess up if one uses too many
 * data-registers to hold input values and one tries to
 * specify d0 and d1 as scratch registers. Letting gcc
 * choose these registers itself solves the problem.
 */


/* Revised by Kenneth Albanowski for m68knommu. Basic problem: unaligned access
 kills, so most of the assembly has to go. */


#include <linux/export.h>
#include <net/checksum.h>

#include <asm/byteorder.h>

#ifndef do_csum
static unsigned int do_csum(const unsigned char *buff, int len)
{
 int odd;
 unsigned int result = 0;

 if (len <= 0)
  goto out;
 odd = 1 & (unsigned long) buff;
 if (odd) {
#ifdef __LITTLE_ENDIAN
  result += (*buff << 8);
#else
  result = *buff;
#endif
  len--;
  buff++;
 }
 if (len >= 2) {
  if (2 & (unsigned long) buff) {
   result += *(unsigned short *) buff;
   len -= 2;
   buff += 2;
  }
  if (len >= 4) {
   const unsigned char *end = buff + ((unsigned)len & ~3);
   unsigned int carry = 0;
   do {
    unsigned int w = *(unsigned int *) buff;
    buff += 4;
    result += carry;
    result += w;
    carry = (w > result);
   } while (buff < end);
   result += carry;
   result = (result & 0xffff) + (result >> 16);
  }
  if (len & 2) {
   result += *(unsigned short *) buff;
   buff += 2;
  }
 }
 if (len & 1)
#ifdef __LITTLE_ENDIAN
  result += *buff;
#else
  result += (*buff << 8);
#endif
 result = csum_from32to16(result);
 if (odd)
  result = ((result >> 8) & 0xff) | ((result & 0xff) << 8);
out:
 return result;
}
#endif

#ifndef ip_fast_csum
/*
 * This is a version of ip_compute_csum() optimized for IP headers,
 * which always checksum on 4 octet boundaries.
 */

__sum16 ip_fast_csum(const void *iph, unsigned int ihl)
{
 return (__force __sum16)~do_csum(iph, ihl*4);
}
EXPORT_SYMBOL(ip_fast_csum);
#endif

/*
 * computes the checksum of a memory block at buff, length len,
 * and adds in "sum" (32-bit)
 *
 * returns a 32-bit number suitable for feeding into itself
 * or csum_tcpudp_magic
 *
 * this function must be called with even lengths, except
 * for the last fragment, which may be odd
 *
 * it's best to have buff aligned on a 32-bit boundary
 */

__wsum csum_partial(const void *buff, int len, __wsum wsum)
{
 unsigned int sum = (__force unsigned int)wsum;
 unsigned int result = do_csum(buff, len);

 /* add in old sum, and carry.. */
 result += sum;
 if (sum > result)
  result += 1;
 return (__force __wsum)result;
}
EXPORT_SYMBOL(csum_partial);

/*
 * this routine is used for miscellaneous IP-like checksums, mainly
 * in icmp.c
 */

__sum16 ip_compute_csum(const void *buff, int len)
{
 return (__force __sum16)~do_csum(buff, len);
}
EXPORT_SYMBOL(ip_compute_csum);

#ifndef csum_tcpudp_nofold
static inline u32 from64to32(u64 x)
{
 /* add up 32-bit and 32-bit for 32+c bit */
 x = (x & 0xffffffff) + (x >> 32);
 /* add up carry.. */
 x = (x & 0xffffffff) + (x >> 32);
 return (u32)x;
}

__wsum csum_tcpudp_nofold(__be32 saddr, __be32 daddr,
     __u32 len, __u8 proto, __wsum sum)
{
 unsigned long long s = (__force u32)sum;

 s += (__force u32)saddr;
 s += (__force u32)daddr;
#ifdef __BIG_ENDIAN
 s += proto + len;
#else
 s += (proto + len) << 8;
#endif
 return (__force __wsum)from64to32(s);
}
EXPORT_SYMBOL(csum_tcpudp_nofold);
#endif

Messung V0.5
C=88 H=93 G=90

¤ Dauer der Verarbeitung: 0.4 Sekunden  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.