linux/arch/blackfin/lib/checksum.c
<<
>>
Prefs
   1/*
   2 * Copyright 2004-2009 Analog Devices Inc.
   3 *
   4 * Licensed under the GPL-2 or later.
   5 *
   6 * An implementation of the TCP/IP protocol suite for the LINUX operating
   7 * system. INET is implemented using the BSD Socket interface as the
   8 * means of communication with the user level.
   9 *
  10 */
  11
  12#include <linux/module.h>
  13#include <net/checksum.h>
  14#include <asm/checksum.h>
  15
  16#ifdef CONFIG_IP_CHECKSUM_L1
  17static unsigned short do_csum(const unsigned char *buff, int len)__attribute__((l1_text));
  18#endif
  19
  20static unsigned short do_csum(const unsigned char *buff, int len)
  21{
  22        register unsigned long sum = 0;
  23        int swappem = 0;
  24
  25        if (1 & (unsigned long)buff) {
  26                sum = *buff << 8;
  27                buff++;
  28                len--;
  29                ++swappem;
  30        }
  31
  32        while (len > 1) {
  33                sum += *(unsigned short *)buff;
  34                buff += 2;
  35                len -= 2;
  36        }
  37
  38        if (len > 0)
  39                sum += *buff;
  40
  41        /*  Fold 32-bit sum to 16 bits */
  42        while (sum >> 16)
  43                sum = (sum & 0xffff) + (sum >> 16);
  44
  45        if (swappem)
  46                sum = ((sum & 0xff00) >> 8) + ((sum & 0x00ff) << 8);
  47
  48        return sum;
  49
  50}
  51
  52/*
  53 *      This is a version of ip_compute_csum() optimized for IP headers,
  54 *      which always checksum on 4 octet boundaries.
  55 */
  56__sum16 ip_fast_csum(unsigned char *iph, unsigned int ihl)
  57{
  58        return (__force __sum16)~do_csum(iph, ihl * 4);
  59}
  60EXPORT_SYMBOL(ip_fast_csum);
  61
  62/*
  63 * computes the checksum of a memory block at buff, length len,
  64 * and adds in "sum" (32-bit)
  65 *
  66 * returns a 32-bit number suitable for feeding into itself
  67 * or csum_tcpudp_magic
  68 *
  69 * this function must be called with even lengths, except
  70 * for the last fragment, which may be odd
  71 *
  72 * it's best to have buff aligned on a 32-bit boundary
  73 */
  74__wsum csum_partial(const void *buff, int len, __wsum sum)
  75{
  76        /*
  77         * Just in case we get nasty checksum data...
  78         * Like 0xffff6ec3 in the case of our IPv6 multicast header.
  79         * We fold to begin with, as well as at the end.
  80         */
  81        sum = (sum & 0xffff) + (sum >> 16);
  82
  83        sum += do_csum(buff, len);
  84
  85        sum = (sum & 0xffff) + (sum >> 16);
  86
  87        return sum;
  88}
  89EXPORT_SYMBOL(csum_partial);
  90
  91/*
  92 * this routine is used for miscellaneous IP-like checksums, mainly
  93 * in icmp.c
  94 */
  95__sum16 ip_compute_csum(const void *buff, int len)
  96{
  97        return (__force __sum16)~do_csum(buff, len);
  98}
  99EXPORT_SYMBOL(ip_compute_csum);
 100
 101/*
 102 * copy from fs while checksumming, otherwise like csum_partial
 103 */
 104
 105__wsum
 106csum_partial_copy_from_user(const void __user *src, void *dst,
 107                            int len, __wsum sum, int *csum_err)
 108{
 109        if (csum_err)
 110                *csum_err = 0;
 111        memcpy(dst, (__force void *)src, len);
 112        return csum_partial(dst, len, sum);
 113}
 114EXPORT_SYMBOL(csum_partial_copy_from_user);
 115
 116/*
 117 * copy from ds while checksumming, otherwise like csum_partial
 118 */
 119
 120__wsum csum_partial_copy(const void *src, void *dst, int len, __wsum sum)
 121{
 122        memcpy(dst, src, len);
 123        return csum_partial(dst, len, sum);
 124}
 125EXPORT_SYMBOL(csum_partial_copy);
 126