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