1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* xfrm4_tunnel.c: Generic IP tunnel transformer. |
3 | * |
4 | * Copyright (C) 2003 David S. Miller (davem@redhat.com) |
5 | */ |
6 | |
7 | #define pr_fmt(fmt) "IPsec: " fmt |
8 | |
9 | #include <linux/skbuff.h> |
10 | #include <linux/module.h> |
11 | #include <net/xfrm.h> |
12 | #include <net/protocol.h> |
13 | |
14 | static int ipip_output(struct xfrm_state *x, struct sk_buff *skb) |
15 | { |
16 | skb_push(skb, len: -skb_network_offset(skb)); |
17 | return 0; |
18 | } |
19 | |
20 | static int ipip_xfrm_rcv(struct xfrm_state *x, struct sk_buff *skb) |
21 | { |
22 | return ip_hdr(skb)->protocol; |
23 | } |
24 | |
25 | static int ipip_init_state(struct xfrm_state *x, struct netlink_ext_ack *extack) |
26 | { |
27 | if (x->props.mode != XFRM_MODE_TUNNEL) { |
28 | NL_SET_ERR_MSG(extack, "IPv4 tunnel can only be used with tunnel mode" ); |
29 | return -EINVAL; |
30 | } |
31 | |
32 | if (x->encap) { |
33 | NL_SET_ERR_MSG(extack, "IPv4 tunnel is not compatible with encapsulation" ); |
34 | return -EINVAL; |
35 | } |
36 | |
37 | x->props.header_len = sizeof(struct iphdr); |
38 | |
39 | return 0; |
40 | } |
41 | |
42 | static void ipip_destroy(struct xfrm_state *x) |
43 | { |
44 | } |
45 | |
46 | static const struct xfrm_type ipip_type = { |
47 | .owner = THIS_MODULE, |
48 | .proto = IPPROTO_IPIP, |
49 | .init_state = ipip_init_state, |
50 | .destructor = ipip_destroy, |
51 | .input = ipip_xfrm_rcv, |
52 | .output = ipip_output |
53 | }; |
54 | |
55 | static int xfrm_tunnel_rcv(struct sk_buff *skb) |
56 | { |
57 | return xfrm4_rcv_spi(skb, IPPROTO_IPIP, spi: ip_hdr(skb)->saddr); |
58 | } |
59 | |
60 | static int xfrm_tunnel_err(struct sk_buff *skb, u32 info) |
61 | { |
62 | return -ENOENT; |
63 | } |
64 | |
65 | static struct xfrm_tunnel xfrm_tunnel_handler __read_mostly = { |
66 | .handler = xfrm_tunnel_rcv, |
67 | .err_handler = xfrm_tunnel_err, |
68 | .priority = 4, |
69 | }; |
70 | |
71 | #if IS_ENABLED(CONFIG_IPV6) |
72 | static struct xfrm_tunnel xfrm64_tunnel_handler __read_mostly = { |
73 | .handler = xfrm_tunnel_rcv, |
74 | .err_handler = xfrm_tunnel_err, |
75 | .priority = 3, |
76 | }; |
77 | #endif |
78 | |
79 | static int __init ipip_init(void) |
80 | { |
81 | if (xfrm_register_type(type: &ipip_type, AF_INET) < 0) { |
82 | pr_info("%s: can't add xfrm type\n" , __func__); |
83 | return -EAGAIN; |
84 | } |
85 | |
86 | if (xfrm4_tunnel_register(handler: &xfrm_tunnel_handler, AF_INET)) { |
87 | pr_info("%s: can't add xfrm handler for AF_INET\n" , __func__); |
88 | xfrm_unregister_type(type: &ipip_type, AF_INET); |
89 | return -EAGAIN; |
90 | } |
91 | #if IS_ENABLED(CONFIG_IPV6) |
92 | if (xfrm4_tunnel_register(handler: &xfrm64_tunnel_handler, AF_INET6)) { |
93 | pr_info("%s: can't add xfrm handler for AF_INET6\n" , __func__); |
94 | xfrm4_tunnel_deregister(handler: &xfrm_tunnel_handler, AF_INET); |
95 | xfrm_unregister_type(type: &ipip_type, AF_INET); |
96 | return -EAGAIN; |
97 | } |
98 | #endif |
99 | return 0; |
100 | } |
101 | |
102 | static void __exit ipip_fini(void) |
103 | { |
104 | #if IS_ENABLED(CONFIG_IPV6) |
105 | if (xfrm4_tunnel_deregister(handler: &xfrm64_tunnel_handler, AF_INET6)) |
106 | pr_info("%s: can't remove xfrm handler for AF_INET6\n" , |
107 | __func__); |
108 | #endif |
109 | if (xfrm4_tunnel_deregister(handler: &xfrm_tunnel_handler, AF_INET)) |
110 | pr_info("%s: can't remove xfrm handler for AF_INET\n" , |
111 | __func__); |
112 | xfrm_unregister_type(type: &ipip_type, AF_INET); |
113 | } |
114 | |
115 | module_init(ipip_init); |
116 | module_exit(ipip_fini); |
117 | MODULE_LICENSE("GPL" ); |
118 | MODULE_ALIAS_XFRM_TYPE(AF_INET, XFRM_PROTO_IPIP); |
119 | |