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 : 0 : static inline struct xfrm4_protocol __rcu **proto_handlers(u8 protocol)
27 : : {
28 : 0 : switch (protocol) {
29 : : case IPPROTO_ESP:
30 : : return &esp4_handlers;
31 : 0 : case IPPROTO_AH:
32 : 0 : return &ah4_handlers;
33 : 0 : case IPPROTO_COMP:
34 : 0 : return &ipcomp4_handlers;
35 : : }
36 : :
37 : 0 : 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 : 0 : int ret;
48 : 0 : struct xfrm4_protocol *handler;
49 [ # # # # ]: 0 : 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 : 0 : int ret;
65 : 0 : 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 : 0 : goto out;
74 : :
75 [ # # ]: 0 : if (!skb_dst(skb)) {
76 : 0 : const struct iphdr *iph = ip_hdr(skb);
77 : :
78 [ # # ]: 0 : if (ip_route_input_noref(skb, iph->daddr, iph->saddr,
79 : 0 : iph->tos, skb->dev))
80 : 0 : goto drop;
81 : : }
82 : :
83 [ # # ]: 0 : for_each_protocol_rcu(*head, handler)
84 [ # # ]: 0 : if ((ret = handler->input_handler(skb, nexthdr, spi, encap_type)) != -EINVAL)
85 : 0 : return ret;
86 : :
87 : 0 : out:
88 : 0 : icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0);
89 : :
90 : 0 : drop:
91 : 0 : kfree_skb(skb);
92 : 0 : return 0;
93 : : }
94 : : EXPORT_SYMBOL(xfrm4_rcv_encap);
95 : :
96 : 0 : static int xfrm4_esp_rcv(struct sk_buff *skb)
97 : : {
98 : 0 : int ret;
99 : 0 : struct xfrm4_protocol *handler;
100 : :
101 : 0 : XFRM_TUNNEL_SKB_CB(skb)->tunnel.ip4 = NULL;
102 : :
103 [ # # ]: 0 : for_each_protocol_rcu(esp4_handlers, handler)
104 [ # # ]: 0 : if ((ret = handler->handler(skb)) != -EINVAL)
105 : 0 : return ret;
106 : :
107 : 0 : icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0);
108 : :
109 : 0 : kfree_skb(skb);
110 : 0 : return 0;
111 : : }
112 : :
113 : 0 : static int xfrm4_esp_err(struct sk_buff *skb, u32 info)
114 : : {
115 : 0 : struct xfrm4_protocol *handler;
116 : :
117 [ # # ]: 0 : for_each_protocol_rcu(esp4_handlers, handler)
118 [ # # ]: 0 : if (!handler->err_handler(skb, info))
119 : : return 0;
120 : :
121 : : return -ENOENT;
122 : : }
123 : :
124 : 0 : static int xfrm4_ah_rcv(struct sk_buff *skb)
125 : : {
126 : 0 : int ret;
127 : 0 : struct xfrm4_protocol *handler;
128 : :
129 : 0 : XFRM_TUNNEL_SKB_CB(skb)->tunnel.ip4 = NULL;
130 : :
131 [ # # ]: 0 : for_each_protocol_rcu(ah4_handlers, handler)
132 [ # # ]: 0 : if ((ret = handler->handler(skb)) != -EINVAL)
133 : 0 : return ret;
134 : :
135 : 0 : icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0);
136 : :
137 : 0 : kfree_skb(skb);
138 : 0 : return 0;
139 : : }
140 : :
141 : 0 : static int xfrm4_ah_err(struct sk_buff *skb, u32 info)
142 : : {
143 : 0 : struct xfrm4_protocol *handler;
144 : :
145 [ # # ]: 0 : for_each_protocol_rcu(ah4_handlers, handler)
146 [ # # ]: 0 : if (!handler->err_handler(skb, info))
147 : : return 0;
148 : :
149 : : return -ENOENT;
150 : : }
151 : :
152 : 0 : static int xfrm4_ipcomp_rcv(struct sk_buff *skb)
153 : : {
154 : 0 : int ret;
155 : 0 : struct xfrm4_protocol *handler;
156 : :
157 : 0 : XFRM_TUNNEL_SKB_CB(skb)->tunnel.ip4 = NULL;
158 : :
159 [ # # ]: 0 : for_each_protocol_rcu(ipcomp4_handlers, handler)
160 [ # # ]: 0 : if ((ret = handler->handler(skb)) != -EINVAL)
161 : 0 : return ret;
162 : :
163 : 0 : icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0);
164 : :
165 : 0 : kfree_skb(skb);
166 : 0 : return 0;
167 : : }
168 : :
169 : 0 : static int xfrm4_ipcomp_err(struct sk_buff *skb, u32 info)
170 : : {
171 : 0 : struct xfrm4_protocol *handler;
172 : :
173 [ # # ]: 0 : for_each_protocol_rcu(ipcomp4_handlers, handler)
174 [ # # ]: 0 : if (!handler->err_handler(skb, info))
175 : : return 0;
176 : :
177 : : return -ENOENT;
178 : : }
179 : :
180 : : static const struct net_protocol esp4_protocol = {
181 : : .handler = xfrm4_esp_rcv,
182 : : .err_handler = xfrm4_esp_err,
183 : : .no_policy = 1,
184 : : .netns_ok = 1,
185 : : };
186 : :
187 : : static const struct net_protocol ah4_protocol = {
188 : : .handler = xfrm4_ah_rcv,
189 : : .err_handler = xfrm4_ah_err,
190 : : .no_policy = 1,
191 : : .netns_ok = 1,
192 : : };
193 : :
194 : : static const struct net_protocol ipcomp4_protocol = {
195 : : .handler = xfrm4_ipcomp_rcv,
196 : : .err_handler = xfrm4_ipcomp_err,
197 : : .no_policy = 1,
198 : : .netns_ok = 1,
199 : : };
200 : :
201 : : static const struct xfrm_input_afinfo xfrm4_input_afinfo = {
202 : : .family = AF_INET,
203 : : .callback = xfrm4_rcv_cb,
204 : : };
205 : :
206 : 0 : static inline const struct net_protocol *netproto(unsigned char protocol)
207 : : {
208 [ # # # # ]: 0 : switch (protocol) {
209 : : case IPPROTO_ESP:
210 : : return &esp4_protocol;
211 : 0 : case IPPROTO_AH:
212 : 0 : return &ah4_protocol;
213 : 0 : case IPPROTO_COMP:
214 : 0 : return &ipcomp4_protocol;
215 : : }
216 : :
217 : 0 : return NULL;
218 : : }
219 : :
220 : 0 : int xfrm4_protocol_register(struct xfrm4_protocol *handler,
221 : : unsigned char protocol)
222 : : {
223 : 0 : struct xfrm4_protocol __rcu **pprev;
224 : 0 : struct xfrm4_protocol *t;
225 : 0 : bool add_netproto = false;
226 : 0 : int ret = -EEXIST;
227 : 0 : int priority = handler->priority;
228 : :
229 [ # # ]: 0 : if (!proto_handlers(protocol) || !netproto(protocol))
230 : : return -EINVAL;
231 : :
232 : 0 : mutex_lock(&xfrm4_protocol_mutex);
233 : :
234 [ # # # # : 0 : if (!rcu_dereference_protected(*proto_handlers(protocol),
# # ]
235 : : lockdep_is_held(&xfrm4_protocol_mutex)))
236 : 0 : add_netproto = true;
237 : :
238 [ # # # # ]: 0 : for (pprev = proto_handlers(protocol);
239 [ # # ]: 0 : (t = rcu_dereference_protected(*pprev,
240 : : lockdep_is_held(&xfrm4_protocol_mutex))) != NULL;
241 : 0 : pprev = &t->next) {
242 [ # # ]: 0 : if (t->priority < priority)
243 : : break;
244 [ # # ]: 0 : if (t->priority == priority)
245 : 0 : goto err;
246 : : }
247 : :
248 : 0 : handler->next = *pprev;
249 : 0 : rcu_assign_pointer(*pprev, handler);
250 : :
251 : 0 : ret = 0;
252 : :
253 : 0 : err:
254 : 0 : mutex_unlock(&xfrm4_protocol_mutex);
255 : :
256 [ # # ]: 0 : if (add_netproto) {
257 [ # # # # : 0 : if (inet_add_protocol(netproto(protocol), protocol)) {
# # ]
258 : 0 : pr_err("%s: can't add protocol\n", __func__);
259 : 0 : ret = -EAGAIN;
260 : : }
261 : : }
262 : :
263 : : return ret;
264 : : }
265 : : EXPORT_SYMBOL(xfrm4_protocol_register);
266 : :
267 : 0 : int xfrm4_protocol_deregister(struct xfrm4_protocol *handler,
268 : : unsigned char protocol)
269 : : {
270 : 0 : struct xfrm4_protocol __rcu **pprev;
271 : 0 : struct xfrm4_protocol *t;
272 : 0 : int ret = -ENOENT;
273 : :
274 [ # # ]: 0 : if (!proto_handlers(protocol) || !netproto(protocol))
275 : : return -EINVAL;
276 : :
277 : 0 : mutex_lock(&xfrm4_protocol_mutex);
278 : :
279 [ # # # # ]: 0 : for (pprev = proto_handlers(protocol);
280 [ # # ]: 0 : (t = rcu_dereference_protected(*pprev,
281 : : lockdep_is_held(&xfrm4_protocol_mutex))) != NULL;
282 : 0 : pprev = &t->next) {
283 [ # # ]: 0 : if (t == handler) {
284 : 0 : *pprev = handler->next;
285 : 0 : ret = 0;
286 : 0 : break;
287 : : }
288 : : }
289 : :
290 [ # # # # : 0 : if (!rcu_dereference_protected(*proto_handlers(protocol),
# # ]
291 : : lockdep_is_held(&xfrm4_protocol_mutex))) {
292 [ # # # # : 0 : if (inet_del_protocol(netproto(protocol), protocol) < 0) {
# # ]
293 : 0 : pr_err("%s: can't remove protocol\n", __func__);
294 : 0 : ret = -EAGAIN;
295 : : }
296 : : }
297 : :
298 : 0 : mutex_unlock(&xfrm4_protocol_mutex);
299 : :
300 : 0 : synchronize_net();
301 : :
302 : 0 : return ret;
303 : : }
304 : : EXPORT_SYMBOL(xfrm4_protocol_deregister);
305 : :
306 : 3 : void __init xfrm4_protocol_init(void)
307 : : {
308 : 3 : xfrm_input_register_afinfo(&xfrm4_input_afinfo);
309 : 3 : }
310 : : EXPORT_SYMBOL(xfrm4_protocol_init);
|