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

ipcomp6.c (4983B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3 * IP Payload Compression Protocol (IPComp) for IPv6 - RFC3173
      4 *
      5 * Copyright (C)2003 USAGI/WIDE Project
      6 *
      7 * Author	Mitsuru KANDA  <mk@linux-ipv6.org>
      8 */
      9/*
     10 * [Memo]
     11 *
     12 * Outbound:
     13 *  The compression of IP datagram MUST be done before AH/ESP processing,
     14 *  fragmentation, and the addition of Hop-by-Hop/Routing header.
     15 *
     16 * Inbound:
     17 *  The decompression of IP datagram MUST be done after the reassembly,
     18 *  AH/ESP processing.
     19 */
     20
     21#define pr_fmt(fmt) "IPv6: " fmt
     22
     23#include <linux/module.h>
     24#include <net/ip.h>
     25#include <net/xfrm.h>
     26#include <net/ipcomp.h>
     27#include <linux/crypto.h>
     28#include <linux/err.h>
     29#include <linux/pfkeyv2.h>
     30#include <linux/random.h>
     31#include <linux/percpu.h>
     32#include <linux/smp.h>
     33#include <linux/list.h>
     34#include <linux/vmalloc.h>
     35#include <linux/rtnetlink.h>
     36#include <net/ip6_route.h>
     37#include <net/icmp.h>
     38#include <net/ipv6.h>
     39#include <net/protocol.h>
     40#include <linux/ipv6.h>
     41#include <linux/icmpv6.h>
     42#include <linux/mutex.h>
     43
     44static int ipcomp6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
     45				u8 type, u8 code, int offset, __be32 info)
     46{
     47	struct net *net = dev_net(skb->dev);
     48	__be32 spi;
     49	const struct ipv6hdr *iph = (const struct ipv6hdr *)skb->data;
     50	struct ip_comp_hdr *ipcomph =
     51		(struct ip_comp_hdr *)(skb->data + offset);
     52	struct xfrm_state *x;
     53
     54	if (type != ICMPV6_PKT_TOOBIG &&
     55	    type != NDISC_REDIRECT)
     56		return 0;
     57
     58	spi = htonl(ntohs(ipcomph->cpi));
     59	x = xfrm_state_lookup(net, skb->mark, (const xfrm_address_t *)&iph->daddr,
     60			      spi, IPPROTO_COMP, AF_INET6);
     61	if (!x)
     62		return 0;
     63
     64	if (type == NDISC_REDIRECT)
     65		ip6_redirect(skb, net, skb->dev->ifindex, 0,
     66			     sock_net_uid(net, NULL));
     67	else
     68		ip6_update_pmtu(skb, net, info, 0, 0, sock_net_uid(net, NULL));
     69	xfrm_state_put(x);
     70
     71	return 0;
     72}
     73
     74static struct xfrm_state *ipcomp6_tunnel_create(struct xfrm_state *x)
     75{
     76	struct net *net = xs_net(x);
     77	struct xfrm_state *t = NULL;
     78
     79	t = xfrm_state_alloc(net);
     80	if (!t)
     81		goto out;
     82
     83	t->id.proto = IPPROTO_IPV6;
     84	t->id.spi = xfrm6_tunnel_alloc_spi(net, (xfrm_address_t *)&x->props.saddr);
     85	if (!t->id.spi)
     86		goto error;
     87
     88	memcpy(t->id.daddr.a6, x->id.daddr.a6, sizeof(struct in6_addr));
     89	memcpy(&t->sel, &x->sel, sizeof(t->sel));
     90	t->props.family = AF_INET6;
     91	t->props.mode = x->props.mode;
     92	memcpy(t->props.saddr.a6, x->props.saddr.a6, sizeof(struct in6_addr));
     93	memcpy(&t->mark, &x->mark, sizeof(t->mark));
     94	t->if_id = x->if_id;
     95
     96	if (xfrm_init_state(t))
     97		goto error;
     98
     99	atomic_set(&t->tunnel_users, 1);
    100
    101out:
    102	return t;
    103
    104error:
    105	t->km.state = XFRM_STATE_DEAD;
    106	xfrm_state_put(t);
    107	t = NULL;
    108	goto out;
    109}
    110
    111static int ipcomp6_tunnel_attach(struct xfrm_state *x)
    112{
    113	struct net *net = xs_net(x);
    114	int err = 0;
    115	struct xfrm_state *t = NULL;
    116	__be32 spi;
    117	u32 mark = x->mark.m & x->mark.v;
    118
    119	spi = xfrm6_tunnel_spi_lookup(net, (xfrm_address_t *)&x->props.saddr);
    120	if (spi)
    121		t = xfrm_state_lookup(net, mark, (xfrm_address_t *)&x->id.daddr,
    122					      spi, IPPROTO_IPV6, AF_INET6);
    123	if (!t) {
    124		t = ipcomp6_tunnel_create(x);
    125		if (!t) {
    126			err = -EINVAL;
    127			goto out;
    128		}
    129		xfrm_state_insert(t);
    130		xfrm_state_hold(t);
    131	}
    132	x->tunnel = t;
    133	atomic_inc(&t->tunnel_users);
    134
    135out:
    136	return err;
    137}
    138
    139static int ipcomp6_init_state(struct xfrm_state *x)
    140{
    141	int err = -EINVAL;
    142
    143	x->props.header_len = 0;
    144	switch (x->props.mode) {
    145	case XFRM_MODE_TRANSPORT:
    146		break;
    147	case XFRM_MODE_TUNNEL:
    148		x->props.header_len += sizeof(struct ipv6hdr);
    149		break;
    150	default:
    151		goto out;
    152	}
    153
    154	err = ipcomp_init_state(x);
    155	if (err)
    156		goto out;
    157
    158	if (x->props.mode == XFRM_MODE_TUNNEL) {
    159		err = ipcomp6_tunnel_attach(x);
    160		if (err)
    161			goto out;
    162	}
    163
    164	err = 0;
    165out:
    166	return err;
    167}
    168
    169static int ipcomp6_rcv_cb(struct sk_buff *skb, int err)
    170{
    171	return 0;
    172}
    173
    174static const struct xfrm_type ipcomp6_type = {
    175	.owner		= THIS_MODULE,
    176	.proto		= IPPROTO_COMP,
    177	.init_state	= ipcomp6_init_state,
    178	.destructor	= ipcomp_destroy,
    179	.input		= ipcomp_input,
    180	.output		= ipcomp_output,
    181};
    182
    183static struct xfrm6_protocol ipcomp6_protocol = {
    184	.handler	= xfrm6_rcv,
    185	.input_handler	= xfrm_input,
    186	.cb_handler	= ipcomp6_rcv_cb,
    187	.err_handler	= ipcomp6_err,
    188	.priority	= 0,
    189};
    190
    191static int __init ipcomp6_init(void)
    192{
    193	if (xfrm_register_type(&ipcomp6_type, AF_INET6) < 0) {
    194		pr_info("%s: can't add xfrm type\n", __func__);
    195		return -EAGAIN;
    196	}
    197	if (xfrm6_protocol_register(&ipcomp6_protocol, IPPROTO_COMP) < 0) {
    198		pr_info("%s: can't add protocol\n", __func__);
    199		xfrm_unregister_type(&ipcomp6_type, AF_INET6);
    200		return -EAGAIN;
    201	}
    202	return 0;
    203}
    204
    205static void __exit ipcomp6_fini(void)
    206{
    207	if (xfrm6_protocol_deregister(&ipcomp6_protocol, IPPROTO_COMP) < 0)
    208		pr_info("%s: can't remove protocol\n", __func__);
    209	xfrm_unregister_type(&ipcomp6_type, AF_INET6);
    210}
    211
    212module_init(ipcomp6_init);
    213module_exit(ipcomp6_fini);
    214MODULE_LICENSE("GPL");
    215MODULE_DESCRIPTION("IP Payload Compression Protocol (IPComp) for IPv6 - RFC3173");
    216MODULE_AUTHOR("Mitsuru KANDA <mk@linux-ipv6.org>");
    217
    218MODULE_ALIAS_XFRM_TYPE(AF_INET6, XFRM_PROTO_COMP);