hc
2025-02-14 bbb9540dc49f70f6b703d1c8d1b85fa5f602d86e
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
// SPDX-License-Identifier: GPL-2.0
/*
 * Network Checksum & Copy routine
 *
 * Copyright (C) 1999, 2003-2004 Hewlett-Packard Co
 *    Stephane Eranian <eranian@hpl.hp.com>
 *
 * Most of the code has been imported from Linux/Alpha
 */
 
#include <linux/module.h>
#include <linux/types.h>
#include <linux/string.h>
 
#include <net/checksum.h>
 
/*
 * XXX Fixme: those 2 inlines are meant for debugging and will go away
 */
static inline unsigned
short from64to16(unsigned long x)
{
   /* add up 32-bit words for 33 bits */
   x = (x & 0xffffffff) + (x >> 32);
   /* add up 16-bit and 17-bit words for 17+c bits */
   x = (x & 0xffff) + (x >> 16);
   /* add up 16-bit and 2-bit for 16+c bit */
   x = (x & 0xffff) + (x >> 16);
   /* add up carry.. */
   x = (x & 0xffff) + (x >> 16);
   return x;
}
 
static inline
unsigned long do_csum_c(const unsigned char * buff, int len, unsigned int psum)
{
   int odd, count;
   unsigned long result = (unsigned long)psum;
 
   if (len <= 0)
       goto out;
   odd = 1 & (unsigned long) buff;
   if (odd) {
       result = *buff << 8;
       len--;
       buff++;
   }
   count = len >> 1;        /* nr of 16-bit words.. */
   if (count) {
       if (2 & (unsigned long) buff) {
           result += *(unsigned short *) buff;
           count--;
           len -= 2;
           buff += 2;
       }
       count >>= 1;        /* nr of 32-bit words.. */
       if (count) {
           if (4 & (unsigned long) buff) {
               result += *(unsigned int *) buff;
               count--;
               len -= 4;
               buff += 4;
           }
           count >>= 1;    /* nr of 64-bit words.. */
           if (count) {
               unsigned long carry = 0;
               do {
                   unsigned long w = *(unsigned long *) buff;
                   count--;
                   buff += 8;
                   result += carry;
                   result += w;
                   carry = (w > result);
               } while (count);
               result += carry;
               result = (result & 0xffffffff) + (result >> 32);
           }
           if (len & 4) {
               result += *(unsigned int *) buff;
               buff += 4;
           }
       }
       if (len & 2) {
           result += *(unsigned short *) buff;
           buff += 2;
       }
   }
   if (len & 1)
       result += *buff;
 
   result = from64to16(result);
 
   if (odd)
       result = ((result >> 8) & 0xff) | ((result & 0xff) << 8);
 
out:
   return result;
}