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

utils.c (5431B)


      1// SPDX-License-Identifier: GPL-2.0
      2#include <linux/kernel.h>
      3#include <linux/netfilter.h>
      4#include <linux/netfilter_ipv4.h>
      5#include <linux/netfilter_ipv6.h>
      6#include <net/netfilter/nf_queue.h>
      7#include <net/ip6_checksum.h>
      8
      9#ifdef CONFIG_INET
     10__sum16 nf_ip_checksum(struct sk_buff *skb, unsigned int hook,
     11		       unsigned int dataoff, u8 protocol)
     12{
     13	const struct iphdr *iph = ip_hdr(skb);
     14	__sum16 csum = 0;
     15
     16	switch (skb->ip_summed) {
     17	case CHECKSUM_COMPLETE:
     18		if (hook != NF_INET_PRE_ROUTING && hook != NF_INET_LOCAL_IN)
     19			break;
     20		if ((protocol != IPPROTO_TCP && protocol != IPPROTO_UDP &&
     21		    !csum_fold(skb->csum)) ||
     22		    !csum_tcpudp_magic(iph->saddr, iph->daddr,
     23				       skb->len - dataoff, protocol,
     24				       skb->csum)) {
     25			skb->ip_summed = CHECKSUM_UNNECESSARY;
     26			break;
     27		}
     28		fallthrough;
     29	case CHECKSUM_NONE:
     30		if (protocol != IPPROTO_TCP && protocol != IPPROTO_UDP)
     31			skb->csum = 0;
     32		else
     33			skb->csum = csum_tcpudp_nofold(iph->saddr, iph->daddr,
     34						       skb->len - dataoff,
     35						       protocol, 0);
     36		csum = __skb_checksum_complete(skb);
     37	}
     38	return csum;
     39}
     40EXPORT_SYMBOL(nf_ip_checksum);
     41#endif
     42
     43static __sum16 nf_ip_checksum_partial(struct sk_buff *skb, unsigned int hook,
     44				      unsigned int dataoff, unsigned int len,
     45				      u8 protocol)
     46{
     47	const struct iphdr *iph = ip_hdr(skb);
     48	__sum16 csum = 0;
     49
     50	switch (skb->ip_summed) {
     51	case CHECKSUM_COMPLETE:
     52		if (len == skb->len - dataoff)
     53			return nf_ip_checksum(skb, hook, dataoff, protocol);
     54		fallthrough;
     55	case CHECKSUM_NONE:
     56		skb->csum = csum_tcpudp_nofold(iph->saddr, iph->daddr, protocol,
     57					       skb->len - dataoff, 0);
     58		skb->ip_summed = CHECKSUM_NONE;
     59		return __skb_checksum_complete_head(skb, dataoff + len);
     60	}
     61	return csum;
     62}
     63
     64__sum16 nf_ip6_checksum(struct sk_buff *skb, unsigned int hook,
     65			unsigned int dataoff, u8 protocol)
     66{
     67	const struct ipv6hdr *ip6h = ipv6_hdr(skb);
     68	__sum16 csum = 0;
     69
     70	switch (skb->ip_summed) {
     71	case CHECKSUM_COMPLETE:
     72		if (hook != NF_INET_PRE_ROUTING && hook != NF_INET_LOCAL_IN)
     73			break;
     74		if (!csum_ipv6_magic(&ip6h->saddr, &ip6h->daddr,
     75				     skb->len - dataoff, protocol,
     76				     csum_sub(skb->csum,
     77					      skb_checksum(skb, 0,
     78							   dataoff, 0)))) {
     79			skb->ip_summed = CHECKSUM_UNNECESSARY;
     80			break;
     81		}
     82		fallthrough;
     83	case CHECKSUM_NONE:
     84		skb->csum = ~csum_unfold(
     85				csum_ipv6_magic(&ip6h->saddr, &ip6h->daddr,
     86					     skb->len - dataoff,
     87					     protocol,
     88					     csum_sub(0,
     89						      skb_checksum(skb, 0,
     90								   dataoff, 0))));
     91		csum = __skb_checksum_complete(skb);
     92	}
     93	return csum;
     94}
     95EXPORT_SYMBOL(nf_ip6_checksum);
     96
     97static __sum16 nf_ip6_checksum_partial(struct sk_buff *skb, unsigned int hook,
     98				       unsigned int dataoff, unsigned int len,
     99				       u8 protocol)
    100{
    101	const struct ipv6hdr *ip6h = ipv6_hdr(skb);
    102	__wsum hsum;
    103	__sum16 csum = 0;
    104
    105	switch (skb->ip_summed) {
    106	case CHECKSUM_COMPLETE:
    107		if (len == skb->len - dataoff)
    108			return nf_ip6_checksum(skb, hook, dataoff, protocol);
    109		fallthrough;
    110	case CHECKSUM_NONE:
    111		hsum = skb_checksum(skb, 0, dataoff, 0);
    112		skb->csum = ~csum_unfold(csum_ipv6_magic(&ip6h->saddr,
    113							 &ip6h->daddr,
    114							 skb->len - dataoff,
    115							 protocol,
    116							 csum_sub(0, hsum)));
    117		skb->ip_summed = CHECKSUM_NONE;
    118		return __skb_checksum_complete_head(skb, dataoff + len);
    119	}
    120	return csum;
    121};
    122
    123__sum16 nf_checksum(struct sk_buff *skb, unsigned int hook,
    124		    unsigned int dataoff, u8 protocol,
    125		    unsigned short family)
    126{
    127	__sum16 csum = 0;
    128
    129	switch (family) {
    130	case AF_INET:
    131		csum = nf_ip_checksum(skb, hook, dataoff, protocol);
    132		break;
    133	case AF_INET6:
    134		csum = nf_ip6_checksum(skb, hook, dataoff, protocol);
    135		break;
    136	}
    137
    138	return csum;
    139}
    140EXPORT_SYMBOL_GPL(nf_checksum);
    141
    142__sum16 nf_checksum_partial(struct sk_buff *skb, unsigned int hook,
    143			    unsigned int dataoff, unsigned int len,
    144			    u8 protocol, unsigned short family)
    145{
    146	__sum16 csum = 0;
    147
    148	switch (family) {
    149	case AF_INET:
    150		csum = nf_ip_checksum_partial(skb, hook, dataoff, len,
    151					      protocol);
    152		break;
    153	case AF_INET6:
    154		csum = nf_ip6_checksum_partial(skb, hook, dataoff, len,
    155					       protocol);
    156		break;
    157	}
    158
    159	return csum;
    160}
    161EXPORT_SYMBOL_GPL(nf_checksum_partial);
    162
    163int nf_route(struct net *net, struct dst_entry **dst, struct flowi *fl,
    164	     bool strict, unsigned short family)
    165{
    166	const struct nf_ipv6_ops *v6ops __maybe_unused;
    167	int ret = 0;
    168
    169	switch (family) {
    170	case AF_INET:
    171		ret = nf_ip_route(net, dst, fl, strict);
    172		break;
    173	case AF_INET6:
    174		ret = nf_ip6_route(net, dst, fl, strict);
    175		break;
    176	}
    177
    178	return ret;
    179}
    180EXPORT_SYMBOL_GPL(nf_route);
    181
    182static int nf_ip_reroute(struct sk_buff *skb, const struct nf_queue_entry *entry)
    183{
    184#ifdef CONFIG_INET
    185	const struct ip_rt_info *rt_info = nf_queue_entry_reroute(entry);
    186
    187	if (entry->state.hook == NF_INET_LOCAL_OUT) {
    188		const struct iphdr *iph = ip_hdr(skb);
    189
    190		if (!(iph->tos == rt_info->tos &&
    191		      skb->mark == rt_info->mark &&
    192		      iph->daddr == rt_info->daddr &&
    193		      iph->saddr == rt_info->saddr))
    194			return ip_route_me_harder(entry->state.net, entry->state.sk,
    195						  skb, RTN_UNSPEC);
    196	}
    197#endif
    198	return 0;
    199}
    200
    201int nf_reroute(struct sk_buff *skb, struct nf_queue_entry *entry)
    202{
    203	const struct nf_ipv6_ops *v6ops;
    204	int ret = 0;
    205
    206	switch (entry->state.pf) {
    207	case AF_INET:
    208		ret = nf_ip_reroute(skb, entry);
    209		break;
    210	case AF_INET6:
    211		v6ops = rcu_dereference(nf_ipv6_ops);
    212		if (v6ops)
    213			ret = v6ops->reroute(skb, entry);
    214		break;
    215	}
    216	return ret;
    217}