blob: bcab48944c15b390c1f7aaad11db1f3895094289 [file] [log] [blame]
Steffen Klassert33287152014-02-21 08:41:08 +01001/* xfrm4_protocol.c - Generic xfrm protocol multiplexer.
2 *
3 * Copyright (C) 2013 secunet Security Networks AG
4 *
5 * Author:
6 * Steffen Klassert <steffen.klassert@secunet.com>
7 *
8 * Based on:
9 * net/ipv4/tunnel4.c
10 *
11 * This program is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU General Public License
13 * as published by the Free Software Foundation; either version
14 * 2 of the License, or (at your option) any later version.
15 */
16
17#include <linux/init.h>
18#include <linux/mutex.h>
19#include <linux/skbuff.h>
20#include <net/icmp.h>
21#include <net/ip.h>
22#include <net/protocol.h>
23#include <net/xfrm.h>
24
25static struct xfrm4_protocol __rcu *esp4_handlers __read_mostly;
26static struct xfrm4_protocol __rcu *ah4_handlers __read_mostly;
27static struct xfrm4_protocol __rcu *ipcomp4_handlers __read_mostly;
28static DEFINE_MUTEX(xfrm4_protocol_mutex);
29
30static inline struct xfrm4_protocol __rcu **proto_handlers(u8 protocol)
31{
32 switch (protocol) {
33 case IPPROTO_ESP:
34 return &esp4_handlers;
35 case IPPROTO_AH:
36 return &ah4_handlers;
37 case IPPROTO_COMP:
38 return &ipcomp4_handlers;
39 }
40
41 return NULL;
42}
43
44#define for_each_protocol_rcu(head, handler) \
45 for (handler = rcu_dereference(head); \
46 handler != NULL; \
47 handler = rcu_dereference(handler->next)) \
48
Florian Westphalbb9cd072019-04-17 11:45:13 +020049static int xfrm4_rcv_cb(struct sk_buff *skb, u8 protocol, int err)
Steffen Klassert33287152014-02-21 08:41:08 +010050{
51 int ret;
52 struct xfrm4_protocol *handler;
Steffen Klassert61622cc2014-04-29 07:50:44 +020053 struct xfrm4_protocol __rcu **head = proto_handlers(protocol);
Steffen Klassert33287152014-02-21 08:41:08 +010054
Steffen Klassert61622cc2014-04-29 07:50:44 +020055 if (!head)
56 return 0;
57
58 for_each_protocol_rcu(*head, handler)
Steffen Klassert33287152014-02-21 08:41:08 +010059 if ((ret = handler->cb_handler(skb, err)) <= 0)
60 return ret;
61
62 return 0;
63}
Steffen Klassert33287152014-02-21 08:41:08 +010064
65int xfrm4_rcv_encap(struct sk_buff *skb, int nexthdr, __be32 spi,
66 int encap_type)
67{
68 int ret;
69 struct xfrm4_protocol *handler;
Steffen Klassert61622cc2014-04-29 07:50:44 +020070 struct xfrm4_protocol __rcu **head = proto_handlers(nexthdr);
Steffen Klassert33287152014-02-21 08:41:08 +010071
Steffen Klassert70be6c92014-02-21 08:41:09 +010072 XFRM_TUNNEL_SKB_CB(skb)->tunnel.ip4 = NULL;
Steffen Klassert33287152014-02-21 08:41:08 +010073 XFRM_SPI_SKB_CB(skb)->family = AF_INET;
74 XFRM_SPI_SKB_CB(skb)->daddroff = offsetof(struct iphdr, daddr);
75
Steffen Klassert61622cc2014-04-29 07:50:44 +020076 if (!head)
77 goto out;
78
79 for_each_protocol_rcu(*head, handler)
Steffen Klassert33287152014-02-21 08:41:08 +010080 if ((ret = handler->input_handler(skb, nexthdr, spi, encap_type)) != -EINVAL)
81 return ret;
82
Steffen Klassert61622cc2014-04-29 07:50:44 +020083out:
Steffen Klassert33287152014-02-21 08:41:08 +010084 icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0);
85
86 kfree_skb(skb);
87 return 0;
88}
89EXPORT_SYMBOL(xfrm4_rcv_encap);
90
91static int xfrm4_esp_rcv(struct sk_buff *skb)
92{
93 int ret;
94 struct xfrm4_protocol *handler;
95
Steffen Klassert70be6c92014-02-21 08:41:09 +010096 XFRM_TUNNEL_SKB_CB(skb)->tunnel.ip4 = NULL;
97
Steffen Klassert33287152014-02-21 08:41:08 +010098 for_each_protocol_rcu(esp4_handlers, handler)
99 if ((ret = handler->handler(skb)) != -EINVAL)
100 return ret;
101
102 icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0);
103
104 kfree_skb(skb);
105 return 0;
106}
107
Stefano Brivio32bbd872018-11-08 12:19:21 +0100108static int xfrm4_esp_err(struct sk_buff *skb, u32 info)
Steffen Klassert33287152014-02-21 08:41:08 +0100109{
110 struct xfrm4_protocol *handler;
111
112 for_each_protocol_rcu(esp4_handlers, handler)
113 if (!handler->err_handler(skb, info))
Stefano Brivio32bbd872018-11-08 12:19:21 +0100114 return 0;
115
116 return -ENOENT;
Steffen Klassert33287152014-02-21 08:41:08 +0100117}
118
119static int xfrm4_ah_rcv(struct sk_buff *skb)
120{
121 int ret;
122 struct xfrm4_protocol *handler;
123
Steffen Klassert70be6c92014-02-21 08:41:09 +0100124 XFRM_TUNNEL_SKB_CB(skb)->tunnel.ip4 = NULL;
125
Steffen Klassert33287152014-02-21 08:41:08 +0100126 for_each_protocol_rcu(ah4_handlers, handler)
127 if ((ret = handler->handler(skb)) != -EINVAL)
Christoph Paasch17593892014-06-28 14:12:44 +0200128 return ret;
Steffen Klassert33287152014-02-21 08:41:08 +0100129
130 icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0);
131
132 kfree_skb(skb);
133 return 0;
134}
135
Stefano Brivio32bbd872018-11-08 12:19:21 +0100136static int xfrm4_ah_err(struct sk_buff *skb, u32 info)
Steffen Klassert33287152014-02-21 08:41:08 +0100137{
138 struct xfrm4_protocol *handler;
139
140 for_each_protocol_rcu(ah4_handlers, handler)
141 if (!handler->err_handler(skb, info))
Stefano Brivio32bbd872018-11-08 12:19:21 +0100142 return 0;
143
144 return -ENOENT;
Steffen Klassert33287152014-02-21 08:41:08 +0100145}
146
147static int xfrm4_ipcomp_rcv(struct sk_buff *skb)
148{
149 int ret;
150 struct xfrm4_protocol *handler;
151
Steffen Klassert70be6c92014-02-21 08:41:09 +0100152 XFRM_TUNNEL_SKB_CB(skb)->tunnel.ip4 = NULL;
153
Steffen Klassert33287152014-02-21 08:41:08 +0100154 for_each_protocol_rcu(ipcomp4_handlers, handler)
155 if ((ret = handler->handler(skb)) != -EINVAL)
156 return ret;
157
158 icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0);
159
160 kfree_skb(skb);
161 return 0;
162}
163
Stefano Brivio32bbd872018-11-08 12:19:21 +0100164static int xfrm4_ipcomp_err(struct sk_buff *skb, u32 info)
Steffen Klassert33287152014-02-21 08:41:08 +0100165{
166 struct xfrm4_protocol *handler;
167
168 for_each_protocol_rcu(ipcomp4_handlers, handler)
169 if (!handler->err_handler(skb, info))
Stefano Brivio32bbd872018-11-08 12:19:21 +0100170 return 0;
171
172 return -ENOENT;
Steffen Klassert33287152014-02-21 08:41:08 +0100173}
174
175static const struct net_protocol esp4_protocol = {
176 .handler = xfrm4_esp_rcv,
177 .err_handler = xfrm4_esp_err,
178 .no_policy = 1,
179 .netns_ok = 1,
180};
181
182static const struct net_protocol ah4_protocol = {
183 .handler = xfrm4_ah_rcv,
184 .err_handler = xfrm4_ah_err,
185 .no_policy = 1,
186 .netns_ok = 1,
187};
188
189static const struct net_protocol ipcomp4_protocol = {
190 .handler = xfrm4_ipcomp_rcv,
191 .err_handler = xfrm4_ipcomp_err,
192 .no_policy = 1,
193 .netns_ok = 1,
194};
195
Florian Westphal960fdfd2017-02-07 14:52:30 +0100196static const struct xfrm_input_afinfo xfrm4_input_afinfo = {
Steffen Klassert2f32b512014-03-14 07:28:07 +0100197 .family = AF_INET,
Steffen Klassert2f32b512014-03-14 07:28:07 +0100198 .callback = xfrm4_rcv_cb,
199};
200
Steffen Klassert33287152014-02-21 08:41:08 +0100201static inline const struct net_protocol *netproto(unsigned char protocol)
202{
203 switch (protocol) {
204 case IPPROTO_ESP:
205 return &esp4_protocol;
206 case IPPROTO_AH:
207 return &ah4_protocol;
208 case IPPROTO_COMP:
209 return &ipcomp4_protocol;
210 }
211
212 return NULL;
213}
214
215int xfrm4_protocol_register(struct xfrm4_protocol *handler,
216 unsigned char protocol)
217{
218 struct xfrm4_protocol __rcu **pprev;
219 struct xfrm4_protocol *t;
220 bool add_netproto = false;
Steffen Klassert33287152014-02-21 08:41:08 +0100221 int ret = -EEXIST;
222 int priority = handler->priority;
223
Steffen Klassert61622cc2014-04-29 07:50:44 +0200224 if (!proto_handlers(protocol) || !netproto(protocol))
225 return -EINVAL;
226
Steffen Klassert33287152014-02-21 08:41:08 +0100227 mutex_lock(&xfrm4_protocol_mutex);
228
229 if (!rcu_dereference_protected(*proto_handlers(protocol),
230 lockdep_is_held(&xfrm4_protocol_mutex)))
231 add_netproto = true;
232
233 for (pprev = proto_handlers(protocol);
234 (t = rcu_dereference_protected(*pprev,
235 lockdep_is_held(&xfrm4_protocol_mutex))) != NULL;
236 pprev = &t->next) {
237 if (t->priority < priority)
238 break;
239 if (t->priority == priority)
240 goto err;
241 }
242
243 handler->next = *pprev;
244 rcu_assign_pointer(*pprev, handler);
245
246 ret = 0;
247
248err:
249 mutex_unlock(&xfrm4_protocol_mutex);
250
251 if (add_netproto) {
252 if (inet_add_protocol(netproto(protocol), protocol)) {
253 pr_err("%s: can't add protocol\n", __func__);
254 ret = -EAGAIN;
255 }
256 }
257
258 return ret;
259}
260EXPORT_SYMBOL(xfrm4_protocol_register);
261
262int xfrm4_protocol_deregister(struct xfrm4_protocol *handler,
263 unsigned char protocol)
264{
265 struct xfrm4_protocol __rcu **pprev;
266 struct xfrm4_protocol *t;
267 int ret = -ENOENT;
268
Steffen Klassert61622cc2014-04-29 07:50:44 +0200269 if (!proto_handlers(protocol) || !netproto(protocol))
270 return -EINVAL;
271
Steffen Klassert33287152014-02-21 08:41:08 +0100272 mutex_lock(&xfrm4_protocol_mutex);
273
274 for (pprev = proto_handlers(protocol);
275 (t = rcu_dereference_protected(*pprev,
276 lockdep_is_held(&xfrm4_protocol_mutex))) != NULL;
277 pprev = &t->next) {
278 if (t == handler) {
279 *pprev = handler->next;
280 ret = 0;
281 break;
282 }
283 }
284
285 if (!rcu_dereference_protected(*proto_handlers(protocol),
286 lockdep_is_held(&xfrm4_protocol_mutex))) {
287 if (inet_del_protocol(netproto(protocol), protocol) < 0) {
288 pr_err("%s: can't remove protocol\n", __func__);
289 ret = -EAGAIN;
290 }
291 }
292
293 mutex_unlock(&xfrm4_protocol_mutex);
294
295 synchronize_net();
296
297 return ret;
298}
299EXPORT_SYMBOL(xfrm4_protocol_deregister);
Steffen Klassert2f32b512014-03-14 07:28:07 +0100300
301void __init xfrm4_protocol_init(void)
302{
303 xfrm_input_register_afinfo(&xfrm4_input_afinfo);
304}
305EXPORT_SYMBOL(xfrm4_protocol_init);