File Index
Files and directories
Sign in
FILE

checksum.c

File preview with syntax highlighting.

linux-6.19.14/arch/parisc/lib/checksum.c C
 1// SPDX-License-Identifier: GPL-2.0-or-later
 2/*
 3 * INET		An implementation of the TCP/IP protocol suite for the LINUX
 4 *		operating system.  INET is implemented using the  BSD Socket
 5 *		interface as the means of communication with the user level.
 6 *
 7 *		MIPS specific IP/TCP/UDP checksumming routines
 8 *
 9 * Authors:	Ralf Baechle, <ralf@waldorf-gmbh.de>
10 *		Lots of code moved from tcp.c and ip.c; see those files
11 *		for more names.
12 */
13#include <linux/module.h>
14#include <linux/types.h>
15
16#include <net/checksum.h>
17#include <asm/byteorder.h>
18#include <asm/string.h>
19#include <linux/uaccess.h>
20
21#define addc(_t,_r)                     \
22	__asm__ __volatile__ (          \
23"       add             %0, %1, %0\n"   \
24"       addc            %0, %%r0, %0\n" \
25	: "=r"(_t)                      \
26	: "r"(_r), "0"(_t));
27
28static inline unsigned int do_csum(const unsigned char * buff, int len)
29{
30	int odd, count;
31	unsigned int result = 0;
32
33	if (len <= 0)
34		goto out;
35	odd = 1 & (unsigned long) buff;
36	if (odd) {
37		result = be16_to_cpu(*buff);
38		len--;
39		buff++;
40	}
41	count = len >> 1;		/* nr of 16-bit words.. */
42	if (count) {
43		if (2 & (unsigned long) buff) {
44			result += *(unsigned short *) buff;
45			count--;
46			len -= 2;
47			buff += 2;
48		}
49		count >>= 1;		/* nr of 32-bit words.. */
50		if (count) {
51			while (count >= 4) {
52				unsigned int r1, r2, r3, r4;
53				r1 = *(unsigned int *)(buff + 0);
54				r2 = *(unsigned int *)(buff + 4);
55				r3 = *(unsigned int *)(buff + 8);
56				r4 = *(unsigned int *)(buff + 12);
57				addc(result, r1);
58				addc(result, r2);
59				addc(result, r3);
60				addc(result, r4);
61				count -= 4;
62				buff += 16;
63			}
64			while (count) {
65				unsigned int w = *(unsigned int *) buff;
66				count--;
67				buff += 4;
68				addc(result, w);
69			}
70			result = (result & 0xffff) + (result >> 16);
71		}
72		if (len & 2) {
73			result += *(unsigned short *) buff;
74			buff += 2;
75		}
76	}
77	if (len & 1)
78		result += le16_to_cpu(*buff);
79	result = csum_from32to16(result);
80	if (odd)
81		result = swab16(result);
82out:
83	return result;
84}
85
86/*
87 * computes a partial checksum, e.g. for TCP/UDP fragments
88 */
89/*
90 * why bother folding?
91 */
92__wsum csum_partial(const void *buff, int len, __wsum sum)
93{
94	unsigned int result = do_csum(buff, len);
95	addc(result, sum);
96	return (__force __wsum)csum_from32to16(result);
97}
98
99EXPORT_SYMBOL(csum_partial);
~/ Read-only file preview.