Branch data Line data Source code
1 : : // SPDX-License-Identifier: GPL-2.0-or-later
2 : : /* xfrm4_protocol.c - Generic xfrm protocol multiplexer.
3 : : *
4 : : * Copyright (C) 2013 secunet Security Networks AG
5 : : *
6 : : * Author:
7 : : * Steffen Klassert <steffen.klassert@secunet.com>
8 : : *
9 : : * Based on:
10 : : * net/ipv4/tunnel4.c
11 : : */
12 : :
13 : : #include <linux/init.h>
14 : : #include <linux/mutex.h>
15 : : #include <linux/skbuff.h>
16 : : #include <net/icmp.h>
17 : : #include <net/ip.h>
18 : : #include <net/protocol.h>
19 : : #include <net/xfrm.h>
20 : :
21 : : static struct xfrm4_protocol __rcu *esp4_handlers __read_mostly;
22 : : static struct xfrm4_protocol __rcu *ah4_handlers __read_mostly;
23 : : static struct xfrm4_protocol __rcu *ipcomp4_handlers __read_mostly;
24 : : static DEFINE_MUTEX(xfrm4_protocol_mutex);
25 : :
26 : : static inline struct xfrm4_protocol __rcu **proto_handlers(u8 protocol)
27 : : {
28 [ # # # # : 0 : switch (protocol) {
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # ]
29 : : case IPPROTO_ESP:
30 : : return &esp4_handlers;
31 : : case IPPROTO_AH:
32 : : return &ah4_handlers;
33 : : case IPPROTO_COMP:
34 : : return &ipcomp4_handlers;
35 : : }
36 : :
37 : : return NULL;
38 : : }
39 : :
40 : : #define for_each_protocol_rcu(head, handler) \
41 : : for (handler = rcu_dereference(head); \
42 : : handler != NULL; \
43 : : handler = rcu_dereference(handler->next)) \
44 : :
45 : 0 : static int xfrm4_rcv_cb(struct sk_buff *skb, u8 protocol, int err)
46 : : {
47 : : int ret;
48 : : struct xfrm4_protocol *handler;
49 : : struct xfrm4_protocol __rcu **head = proto_handlers(protocol);
50 : :
51 [ # # ]: 0 : if (!head)
52 : : return 0;
53 : :
54 [ # # ]: 0 : for_each_protocol_rcu(*head, handler)
55 [ # # ]: 0 : if ((ret = handler->cb_handler(skb, err)) <= 0)
56 : 0 : return ret;
57 : :
58 : : return 0;
59 : : }
60 : :
61 : 0 : int xfrm4_rcv_encap(struct sk_buff *skb, int nexthdr, __be32 spi,
62 : : int encap_type)
63 : : {
64 : : int ret;
65 : : struct xfrm4_protocol *handler;
66 : 0 : struct xfrm4_protocol __rcu **head = proto_handlers(nexthdr);
67 : :
68 : 0 : XFRM_TUNNEL_SKB_CB(skb)->tunnel.ip4 = NULL;
69 : 0 : XFRM_SPI_SKB_CB(skb)->family = AF_INET;
70 : 0 : XFRM_SPI_SKB_CB(skb)->daddroff = offsetof(struct iphdr, daddr);
71 : :
72 [ # # ]: 0 : if (!head)
73 : : goto out;
74 : :
75 [ # # ]: 0 : for_each_protocol_rcu(*head, handler)
76 [ # # ]: 0 : if ((ret = handler->input_handler(skb, nexthdr, spi, encap_type)) != -EINVAL)
77 : 0 : return ret;
78 : :
79 : : out:
80 : : icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0);
81 : :
82 : 0 : kfree_skb(skb);
83 : 0 : return 0;
84 : : }
85 : : EXPORT_SYMBOL(xfrm4_rcv_encap);
86 : :
87 : 0 : static int xfrm4_esp_rcv(struct sk_buff *skb)
88 : : {
89 : : int ret;
90 : : struct xfrm4_protocol *handler;
91 : :
92 : 0 : XFRM_TUNNEL_SKB_CB(skb)->tunnel.ip4 = NULL;
93 : :
94 [ # # ]: 0 : for_each_protocol_rcu(esp4_handlers, handler)
95 [ # # ]: 0 : if ((ret = handler->handler(skb)) != -EINVAL)
96 : 0 : return ret;
97 : :
98 : : icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0);
99 : :
100 : 0 : kfree_skb(skb);
101 : 0 : return 0;
102 : : }
103 : :
104 : 0 : static int xfrm4_esp_err(struct sk_buff *skb, u32 info)
105 : : {
106 : : struct xfrm4_protocol *handler;
107 : :
108 [ # # ]: 0 : for_each_protocol_rcu(esp4_handlers, handler)
109 [ # # ]: 0 : if (!handler->err_handler(skb, info))
110 : : return 0;
111 : :
112 : : return -ENOENT;
113 : : }
114 : :
115 : 0 : static int xfrm4_ah_rcv(struct sk_buff *skb)
116 : : {
117 : : int ret;
118 : : struct xfrm4_protocol *handler;
119 : :
120 : 0 : XFRM_TUNNEL_SKB_CB(skb)->tunnel.ip4 = NULL;
121 : :
122 [ # # ]: 0 : for_each_protocol_rcu(ah4_handlers, handler)
123 [ # # ]: 0 : if ((ret = handler->handler(skb)) != -EINVAL)
124 : 0 : return ret;
125 : :
126 : : icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0);
127 : :
128 : 0 : kfree_skb(skb);
129 : 0 : return 0;
130 : : }
131 : :
132 : 0 : static int xfrm4_ah_err(struct sk_buff *skb, u32 info)
133 : : {
134 : : struct xfrm4_protocol *handler;
135 : :
136 [ # # ]: 0 : for_each_protocol_rcu(ah4_handlers, handler)
137 [ # # ]: 0 : if (!handler->err_handler(skb, info))
138 : : return 0;
139 : :
140 : : return -ENOENT;
141 : : }
142 : :
143 : 0 : static int xfrm4_ipcomp_rcv(struct sk_buff *skb)
144 : : {
145 : : int ret;
146 : : struct xfrm4_protocol *handler;
147 : :
148 : 0 : XFRM_TUNNEL_SKB_CB(skb)->tunnel.ip4 = NULL;
149 : :
150 [ # # ]: 0 : for_each_protocol_rcu(ipcomp4_handlers, handler)
151 [ # # ]: 0 : if ((ret = handler->handler(skb)) != -EINVAL)
152 : 0 : return ret;
153 : :
154 : : icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0);
155 : :
156 : 0 : kfree_skb(skb);
157 : 0 : return 0;
158 : : }
159 : :
160 : 0 : static int xfrm4_ipcomp_err(struct sk_buff *skb, u32 info)
161 : : {
162 : : struct xfrm4_protocol *handler;
163 : :
164 [ # # ]: 0 : for_each_protocol_rcu(ipcomp4_handlers, handler)
165 [ # # ]: 0 : if (!handler->err_handler(skb, info))
166 : : return 0;
167 : :
168 : : return -ENOENT;
169 : : }
170 : :
171 : : static const struct net_protocol esp4_protocol = {
172 : : .handler = xfrm4_esp_rcv,
173 : : .err_handler = xfrm4_esp_err,
174 : : .no_policy = 1,
175 : : .netns_ok = 1,
176 : : };
177 : :
178 : : static const struct net_protocol ah4_protocol = {
179 : : .handler = xfrm4_ah_rcv,
180 : : .err_handler = xfrm4_ah_err,
181 : : .no_policy = 1,
182 : : .netns_ok = 1,
183 : : };
184 : :
185 : : static const struct net_protocol ipcomp4_protocol = {
186 : : .handler = xfrm4_ipcomp_rcv,
187 : : .err_handler = xfrm4_ipcomp_err,
188 : : .no_policy = 1,
189 : : .netns_ok = 1,
190 : : };
191 : :
192 : : static const struct xfrm_input_afinfo xfrm4_input_afinfo = {
193 : : .family = AF_INET,
194 : : .callback = xfrm4_rcv_cb,
195 : : };
196 : :
197 : : static inline const struct net_protocol *netproto(unsigned char protocol)
198 : : {
199 [ # # # # : 0 : switch (protocol) {
# # # # #
# # # # #
# # ]
200 : : case IPPROTO_ESP:
201 : : return &esp4_protocol;
202 : : case IPPROTO_AH:
203 : : return &ah4_protocol;
204 : : case IPPROTO_COMP:
205 : : return &ipcomp4_protocol;
206 : : }
207 : :
208 : : return NULL;
209 : : }
210 : :
211 : 0 : int xfrm4_protocol_register(struct xfrm4_protocol *handler,
212 : : unsigned char protocol)
213 : : {
214 : : struct xfrm4_protocol __rcu **pprev;
215 : : struct xfrm4_protocol *t;
216 : : bool add_netproto = false;
217 : : int ret = -EEXIST;
218 : 0 : int priority = handler->priority;
219 : :
220 [ # # # # ]: 0 : if (!proto_handlers(protocol) || !netproto(protocol))
221 : : return -EINVAL;
222 : :
223 : 0 : mutex_lock(&xfrm4_protocol_mutex);
224 : :
225 [ # # ]: 0 : if (!rcu_dereference_protected(*proto_handlers(protocol),
226 : : lockdep_is_held(&xfrm4_protocol_mutex)))
227 : : add_netproto = true;
228 : :
229 [ # # ]: 0 : for (pprev = proto_handlers(protocol);
230 : 0 : (t = rcu_dereference_protected(*pprev,
231 : : lockdep_is_held(&xfrm4_protocol_mutex))) != NULL;
232 : 0 : pprev = &t->next) {
233 [ # # ]: 0 : if (t->priority < priority)
234 : : break;
235 [ # # ]: 0 : if (t->priority == priority)
236 : : goto err;
237 : : }
238 : :
239 : 0 : handler->next = *pprev;
240 : 0 : rcu_assign_pointer(*pprev, handler);
241 : :
242 : : ret = 0;
243 : :
244 : : err:
245 : 0 : mutex_unlock(&xfrm4_protocol_mutex);
246 : :
247 [ # # ]: 0 : if (add_netproto) {
248 [ # # ]: 0 : if (inet_add_protocol(netproto(protocol), protocol)) {
249 : 0 : pr_err("%s: can't add protocol\n", __func__);
250 : : ret = -EAGAIN;
251 : : }
252 : : }
253 : :
254 : 0 : return ret;
255 : : }
256 : : EXPORT_SYMBOL(xfrm4_protocol_register);
257 : :
258 : 0 : int xfrm4_protocol_deregister(struct xfrm4_protocol *handler,
259 : : unsigned char protocol)
260 : : {
261 : : struct xfrm4_protocol __rcu **pprev;
262 : : struct xfrm4_protocol *t;
263 : : int ret = -ENOENT;
264 : :
265 [ # # # # ]: 0 : if (!proto_handlers(protocol) || !netproto(protocol))
266 : : return -EINVAL;
267 : :
268 : 0 : mutex_lock(&xfrm4_protocol_mutex);
269 : :
270 [ # # ]: 0 : for (pprev = proto_handlers(protocol);
271 : 0 : (t = rcu_dereference_protected(*pprev,
272 : : lockdep_is_held(&xfrm4_protocol_mutex))) != NULL;
273 : 0 : pprev = &t->next) {
274 [ # # ]: 0 : if (t == handler) {
275 : 0 : *pprev = handler->next;
276 : : ret = 0;
277 : 0 : break;
278 : : }
279 : : }
280 : :
281 [ # # ]: 0 : if (!rcu_dereference_protected(*proto_handlers(protocol),
282 : : lockdep_is_held(&xfrm4_protocol_mutex))) {
283 [ # # ]: 0 : if (inet_del_protocol(netproto(protocol), protocol) < 0) {
284 : 0 : pr_err("%s: can't remove protocol\n", __func__);
285 : : ret = -EAGAIN;
286 : : }
287 : : }
288 : :
289 : 0 : mutex_unlock(&xfrm4_protocol_mutex);
290 : :
291 : 0 : synchronize_net();
292 : :
293 : 0 : return ret;
294 : : }
295 : : EXPORT_SYMBOL(xfrm4_protocol_deregister);
296 : :
297 : 207 : void __init xfrm4_protocol_init(void)
298 : : {
299 : 207 : xfrm_input_register_afinfo(&xfrm4_input_afinfo);
300 : 207 : }
301 : : EXPORT_SYMBOL(xfrm4_protocol_init);
|