cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

ip6_checksum.c (3558B)


      1// SPDX-License-Identifier: GPL-2.0
      2#include <net/ip.h>
      3#include <net/udp.h>
      4#include <net/udplite.h>
      5#include <asm/checksum.h>
      6
      7#ifndef _HAVE_ARCH_IPV6_CSUM
      8__sum16 csum_ipv6_magic(const struct in6_addr *saddr,
      9			const struct in6_addr *daddr,
     10			__u32 len, __u8 proto, __wsum csum)
     11{
     12
     13	int carry;
     14	__u32 ulen;
     15	__u32 uproto;
     16	__u32 sum = (__force u32)csum;
     17
     18	sum += (__force u32)saddr->s6_addr32[0];
     19	carry = (sum < (__force u32)saddr->s6_addr32[0]);
     20	sum += carry;
     21
     22	sum += (__force u32)saddr->s6_addr32[1];
     23	carry = (sum < (__force u32)saddr->s6_addr32[1]);
     24	sum += carry;
     25
     26	sum += (__force u32)saddr->s6_addr32[2];
     27	carry = (sum < (__force u32)saddr->s6_addr32[2]);
     28	sum += carry;
     29
     30	sum += (__force u32)saddr->s6_addr32[3];
     31	carry = (sum < (__force u32)saddr->s6_addr32[3]);
     32	sum += carry;
     33
     34	sum += (__force u32)daddr->s6_addr32[0];
     35	carry = (sum < (__force u32)daddr->s6_addr32[0]);
     36	sum += carry;
     37
     38	sum += (__force u32)daddr->s6_addr32[1];
     39	carry = (sum < (__force u32)daddr->s6_addr32[1]);
     40	sum += carry;
     41
     42	sum += (__force u32)daddr->s6_addr32[2];
     43	carry = (sum < (__force u32)daddr->s6_addr32[2]);
     44	sum += carry;
     45
     46	sum += (__force u32)daddr->s6_addr32[3];
     47	carry = (sum < (__force u32)daddr->s6_addr32[3]);
     48	sum += carry;
     49
     50	ulen = (__force u32)htonl((__u32) len);
     51	sum += ulen;
     52	carry = (sum < ulen);
     53	sum += carry;
     54
     55	uproto = (__force u32)htonl(proto);
     56	sum += uproto;
     57	carry = (sum < uproto);
     58	sum += carry;
     59
     60	return csum_fold((__force __wsum)sum);
     61}
     62EXPORT_SYMBOL(csum_ipv6_magic);
     63#endif
     64
     65int udp6_csum_init(struct sk_buff *skb, struct udphdr *uh, int proto)
     66{
     67	int err;
     68
     69	UDP_SKB_CB(skb)->partial_cov = 0;
     70	UDP_SKB_CB(skb)->cscov = skb->len;
     71
     72	if (proto == IPPROTO_UDPLITE) {
     73		err = udplite_checksum_init(skb, uh);
     74		if (err)
     75			return err;
     76
     77		if (UDP_SKB_CB(skb)->partial_cov) {
     78			skb->csum = ip6_compute_pseudo(skb, proto);
     79			return 0;
     80		}
     81	}
     82
     83	/* To support RFC 6936 (allow zero checksum in UDP/IPV6 for tunnels)
     84	 * we accept a checksum of zero here. When we find the socket
     85	 * for the UDP packet we'll check if that socket allows zero checksum
     86	 * for IPv6 (set by socket option).
     87	 *
     88	 * Note, we are only interested in != 0 or == 0, thus the
     89	 * force to int.
     90	 */
     91	err = (__force int)skb_checksum_init_zero_check(skb, proto, uh->check,
     92							ip6_compute_pseudo);
     93	if (err)
     94		return err;
     95
     96	if (skb->ip_summed == CHECKSUM_COMPLETE && !skb->csum_valid) {
     97		/* If SW calculated the value, we know it's bad */
     98		if (skb->csum_complete_sw)
     99			return 1;
    100
    101		/* HW says the value is bad. Let's validate that.
    102		 * skb->csum is no longer the full packet checksum,
    103		 * so don't treat is as such.
    104		 */
    105		skb_checksum_complete_unset(skb);
    106	}
    107
    108	return 0;
    109}
    110EXPORT_SYMBOL(udp6_csum_init);
    111
    112/* Function to set UDP checksum for an IPv6 UDP packet. This is intended
    113 * for the simple case like when setting the checksum for a UDP tunnel.
    114 */
    115void udp6_set_csum(bool nocheck, struct sk_buff *skb,
    116		   const struct in6_addr *saddr,
    117		   const struct in6_addr *daddr, int len)
    118{
    119	struct udphdr *uh = udp_hdr(skb);
    120
    121	if (nocheck)
    122		uh->check = 0;
    123	else if (skb_is_gso(skb))
    124		uh->check = ~udp_v6_check(len, saddr, daddr, 0);
    125	else if (skb->ip_summed == CHECKSUM_PARTIAL) {
    126		uh->check = 0;
    127		uh->check = udp_v6_check(len, saddr, daddr, lco_csum(skb));
    128		if (uh->check == 0)
    129			uh->check = CSUM_MANGLED_0;
    130	} else {
    131		skb->ip_summed = CHECKSUM_PARTIAL;
    132		skb->csum_start = skb_transport_header(skb) - skb->head;
    133		skb->csum_offset = offsetof(struct udphdr, check);
    134		uh->check = ~udp_v6_check(len, saddr, daddr, 0);
    135	}
    136}
    137EXPORT_SYMBOL(udp6_set_csum);