^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) * IP Payload Compression Protocol (IPComp) - RFC3173.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * Copyright (c) 2003 James Morris <jmorris@intercode.com.au>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) * Todo:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) * - Tunable compression parameters.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) * - Compression stats.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) * - Adaptive compression.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include <linux/err.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #include <linux/rtnetlink.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #include <net/ip.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #include <net/xfrm.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) #include <net/icmp.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) #include <net/ipcomp.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) #include <net/protocol.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) #include <net/sock.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) static int ipcomp4_err(struct sk_buff *skb, u32 info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) struct net *net = dev_net(skb->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) __be32 spi;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) const struct iphdr *iph = (const struct iphdr *)skb->data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) struct ip_comp_hdr *ipch = (struct ip_comp_hdr *)(skb->data+(iph->ihl<<2));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) struct xfrm_state *x;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) switch (icmp_hdr(skb)->type) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) case ICMP_DEST_UNREACH:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) if (icmp_hdr(skb)->code != ICMP_FRAG_NEEDED)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) case ICMP_REDIRECT:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) spi = htonl(ntohs(ipch->cpi));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) x = xfrm_state_lookup(net, skb->mark, (const xfrm_address_t *)&iph->daddr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) spi, IPPROTO_COMP, AF_INET);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) if (!x)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) if (icmp_hdr(skb)->type == ICMP_DEST_UNREACH)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) ipv4_update_pmtu(skb, net, info, 0, IPPROTO_COMP);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) ipv4_redirect(skb, net, 0, IPPROTO_COMP);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) xfrm_state_put(x);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) /* We always hold one tunnel user reference to indicate a tunnel */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) static struct xfrm_state *ipcomp_tunnel_create(struct xfrm_state *x)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) struct net *net = xs_net(x);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) struct xfrm_state *t;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) t = xfrm_state_alloc(net);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) if (!t)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) t->id.proto = IPPROTO_IPIP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) t->id.spi = x->props.saddr.a4;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) t->id.daddr.a4 = x->id.daddr.a4;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) memcpy(&t->sel, &x->sel, sizeof(t->sel));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) t->props.family = AF_INET;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) t->props.mode = x->props.mode;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) t->props.saddr.a4 = x->props.saddr.a4;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) t->props.flags = x->props.flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) t->props.extra_flags = x->props.extra_flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) memcpy(&t->mark, &x->mark, sizeof(t->mark));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) t->if_id = x->if_id;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) if (xfrm_init_state(t))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) goto error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) atomic_set(&t->tunnel_users, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) out:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) return t;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) error:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) t->km.state = XFRM_STATE_DEAD;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) xfrm_state_put(t);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) t = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) * Must be protected by xfrm_cfg_mutex. State and tunnel user references are
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) * always incremented on success.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) static int ipcomp_tunnel_attach(struct xfrm_state *x)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) struct net *net = xs_net(x);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) int err = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) struct xfrm_state *t;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) u32 mark = x->mark.v & x->mark.m;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) t = xfrm_state_lookup(net, mark, (xfrm_address_t *)&x->id.daddr.a4,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) x->props.saddr.a4, IPPROTO_IPIP, AF_INET);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) if (!t) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) t = ipcomp_tunnel_create(x);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) if (!t) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) err = -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) xfrm_state_insert(t);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) xfrm_state_hold(t);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) x->tunnel = t;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) atomic_inc(&t->tunnel_users);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) out:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) static int ipcomp4_init_state(struct xfrm_state *x)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) int err = -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) x->props.header_len = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) switch (x->props.mode) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) case XFRM_MODE_TRANSPORT:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) case XFRM_MODE_TUNNEL:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) x->props.header_len += sizeof(struct iphdr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) err = ipcomp_init_state(x);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) if (err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) if (x->props.mode == XFRM_MODE_TUNNEL) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) err = ipcomp_tunnel_attach(x);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) if (err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) err = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) out:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) static int ipcomp4_rcv_cb(struct sk_buff *skb, int err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) static const struct xfrm_type ipcomp_type = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) .description = "IPCOMP4",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) .owner = THIS_MODULE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) .proto = IPPROTO_COMP,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) .init_state = ipcomp4_init_state,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) .destructor = ipcomp_destroy,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) .input = ipcomp_input,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) .output = ipcomp_output
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) static struct xfrm4_protocol ipcomp4_protocol = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) .handler = xfrm4_rcv,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) .input_handler = xfrm_input,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) .cb_handler = ipcomp4_rcv_cb,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) .err_handler = ipcomp4_err,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) .priority = 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) static int __init ipcomp4_init(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) if (xfrm_register_type(&ipcomp_type, AF_INET) < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) pr_info("%s: can't add xfrm type\n", __func__);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) return -EAGAIN;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) if (xfrm4_protocol_register(&ipcomp4_protocol, IPPROTO_COMP) < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) pr_info("%s: can't add protocol\n", __func__);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) xfrm_unregister_type(&ipcomp_type, AF_INET);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) return -EAGAIN;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) static void __exit ipcomp4_fini(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) if (xfrm4_protocol_deregister(&ipcomp4_protocol, IPPROTO_COMP) < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) pr_info("%s: can't remove protocol\n", __func__);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) xfrm_unregister_type(&ipcomp_type, AF_INET);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) module_init(ipcomp4_init);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) module_exit(ipcomp4_fini);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) MODULE_LICENSE("GPL");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) MODULE_DESCRIPTION("IP Payload Compression Protocol (IPComp/IPv4) - RFC3173");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) MODULE_AUTHOR("James Morris <jmorris@intercode.com.au>");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) MODULE_ALIAS_XFRM_TYPE(AF_INET, XFRM_PROTO_COMP);