xref: /linux/net/ipv6/xfrm6_protocol.c (revision fcee7d82f27d6a8b1ddc5bbefda59b4e441e9bc0)
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /* xfrm6_protocol.c - Generic xfrm protocol multiplexer for ipv6.
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/xfrm4_protocol.c
11  */
12 
13 #include <linux/init.h>
14 #include <linux/mutex.h>
15 #include <linux/skbuff.h>
16 #include <linux/icmpv6.h>
17 #include <net/ip6_route.h>
18 #include <net/ipv6.h>
19 #include <net/protocol.h>
20 #include <net/xfrm.h>
21 
22 static struct xfrm6_protocol __rcu *esp6_handlers __read_mostly;
23 static struct xfrm6_protocol __rcu *ah6_handlers __read_mostly;
24 static struct xfrm6_protocol __rcu *ipcomp6_handlers __read_mostly;
25 static DEFINE_MUTEX(xfrm6_protocol_mutex);
26 
proto_handlers(u8 protocol)27 static inline struct xfrm6_protocol __rcu **proto_handlers(u8 protocol)
28 {
29 	switch (protocol) {
30 	case IPPROTO_ESP:
31 		return &esp6_handlers;
32 	case IPPROTO_AH:
33 		return &ah6_handlers;
34 	case IPPROTO_COMP:
35 		return &ipcomp6_handlers;
36 	}
37 
38 	return NULL;
39 }
40 
41 #define for_each_protocol_rcu(head, handler)		\
42 	for (handler = rcu_dereference(head);		\
43 	     handler != NULL;				\
44 	     handler = rcu_dereference(handler->next))	\
45 
xfrm6_rcv_cb(struct sk_buff * skb,u8 protocol,int err)46 static int xfrm6_rcv_cb(struct sk_buff *skb, u8 protocol, int err)
47 {
48 	int ret;
49 	struct xfrm6_protocol *handler;
50 	struct xfrm6_protocol __rcu **head = proto_handlers(protocol);
51 
52 	if (!head)
53 		return 0;
54 
55 	for_each_protocol_rcu(*proto_handlers(protocol), handler)
56 		if ((ret = handler->cb_handler(skb, err)) <= 0)
57 			return ret;
58 
59 	return 0;
60 }
61 
xfrm6_rcv_encap(struct sk_buff * skb,int nexthdr,__be32 spi,int encap_type)62 int xfrm6_rcv_encap(struct sk_buff *skb, int nexthdr, __be32 spi,
63 		    int encap_type)
64 {
65 	int ret;
66 	struct xfrm6_protocol *handler;
67 	struct xfrm6_protocol __rcu **head = proto_handlers(nexthdr);
68 
69 	XFRM_TUNNEL_SKB_CB(skb)->tunnel.ip6 = NULL;
70 	XFRM_SPI_SKB_CB(skb)->family = AF_INET6;
71 	XFRM_SPI_SKB_CB(skb)->daddroff = offsetof(struct ipv6hdr, daddr);
72 
73 	if (!head)
74 		goto out;
75 
76 	if (!skb_dst(skb)) {
77 		const struct ipv6hdr *ip6h = ipv6_hdr(skb);
78 		int flags = RT6_LOOKUP_F_HAS_SADDR;
79 		struct dst_entry *dst;
80 		struct flowi6 fl6 = {
81 			.flowi6_iif   = skb->dev->ifindex,
82 			.daddr        = ip6h->daddr,
83 			.saddr        = ip6h->saddr,
84 			.flowlabel    = ip6_flowinfo(ip6h),
85 			.flowi6_mark  = skb->mark,
86 			.flowi6_proto = ip6h->nexthdr,
87 		};
88 
89 		dst = ip6_route_input_lookup(dev_net(skb->dev), skb->dev, &fl6,
90 					     skb, flags);
91 		if (dst->error) {
92 			dst_release(dst);
93 			goto drop;
94 		}
95 		skb_dst_set(skb, dst);
96 	}
97 
98 	for_each_protocol_rcu(*head, handler)
99 		if ((ret = handler->input_handler(skb, nexthdr, spi, encap_type)) != -EINVAL)
100 			return ret;
101 
102 out:
103 	icmpv6_send(skb, ICMPV6_DEST_UNREACH, ICMPV6_PORT_UNREACH, 0);
104 
105 drop:
106 	kfree_skb(skb);
107 	return 0;
108 }
109 EXPORT_SYMBOL(xfrm6_rcv_encap);
110 
xfrm6_esp_rcv(struct sk_buff * skb)111 static int xfrm6_esp_rcv(struct sk_buff *skb)
112 {
113 	int ret;
114 	struct xfrm6_protocol *handler;
115 
116 	XFRM_TUNNEL_SKB_CB(skb)->tunnel.ip6 = NULL;
117 
118 	for_each_protocol_rcu(esp6_handlers, handler)
119 		if ((ret = handler->handler(skb)) != -EINVAL)
120 			return ret;
121 
122 	icmpv6_send(skb, ICMPV6_DEST_UNREACH, ICMPV6_PORT_UNREACH, 0);
123 
124 	kfree_skb(skb);
125 	return 0;
126 }
127 
xfrm6_esp_err(struct sk_buff * skb,struct inet6_skb_parm * opt,u8 type,u8 code,int offset,__be32 info)128 static int xfrm6_esp_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
129 			  u8 type, u8 code, int offset, __be32 info)
130 {
131 	struct xfrm6_protocol *handler;
132 
133 	for_each_protocol_rcu(esp6_handlers, handler)
134 		if (!handler->err_handler(skb, opt, type, code, offset, info))
135 			return 0;
136 
137 	return -ENOENT;
138 }
139 
xfrm6_ah_rcv(struct sk_buff * skb)140 static int xfrm6_ah_rcv(struct sk_buff *skb)
141 {
142 	int ret;
143 	struct xfrm6_protocol *handler;
144 
145 	XFRM_TUNNEL_SKB_CB(skb)->tunnel.ip6 = NULL;
146 
147 	for_each_protocol_rcu(ah6_handlers, handler)
148 		if ((ret = handler->handler(skb)) != -EINVAL)
149 			return ret;
150 
151 	icmpv6_send(skb, ICMPV6_DEST_UNREACH, ICMPV6_PORT_UNREACH, 0);
152 
153 	kfree_skb(skb);
154 	return 0;
155 }
156 
xfrm6_ah_err(struct sk_buff * skb,struct inet6_skb_parm * opt,u8 type,u8 code,int offset,__be32 info)157 static int xfrm6_ah_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
158 			 u8 type, u8 code, int offset, __be32 info)
159 {
160 	struct xfrm6_protocol *handler;
161 
162 	for_each_protocol_rcu(ah6_handlers, handler)
163 		if (!handler->err_handler(skb, opt, type, code, offset, info))
164 			return 0;
165 
166 	return -ENOENT;
167 }
168 
xfrm6_ipcomp_rcv(struct sk_buff * skb)169 static int xfrm6_ipcomp_rcv(struct sk_buff *skb)
170 {
171 	int ret;
172 	struct xfrm6_protocol *handler;
173 
174 	XFRM_TUNNEL_SKB_CB(skb)->tunnel.ip6 = NULL;
175 
176 	for_each_protocol_rcu(ipcomp6_handlers, handler)
177 		if ((ret = handler->handler(skb)) != -EINVAL)
178 			return ret;
179 
180 	icmpv6_send(skb, ICMPV6_DEST_UNREACH, ICMPV6_PORT_UNREACH, 0);
181 
182 	kfree_skb(skb);
183 	return 0;
184 }
185 
xfrm6_ipcomp_err(struct sk_buff * skb,struct inet6_skb_parm * opt,u8 type,u8 code,int offset,__be32 info)186 static int xfrm6_ipcomp_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
187 			     u8 type, u8 code, int offset, __be32 info)
188 {
189 	struct xfrm6_protocol *handler;
190 
191 	for_each_protocol_rcu(ipcomp6_handlers, handler)
192 		if (!handler->err_handler(skb, opt, type, code, offset, info))
193 			return 0;
194 
195 	return -ENOENT;
196 }
197 
198 static const struct inet6_protocol esp6_protocol = {
199 	.handler	=	xfrm6_esp_rcv,
200 	.err_handler	=	xfrm6_esp_err,
201 	.flags		=	INET6_PROTO_NOPOLICY,
202 };
203 
204 static const struct inet6_protocol ah6_protocol = {
205 	.handler	=	xfrm6_ah_rcv,
206 	.err_handler	=	xfrm6_ah_err,
207 	.flags		=	INET6_PROTO_NOPOLICY,
208 };
209 
210 static const struct inet6_protocol ipcomp6_protocol = {
211 	.handler	=	xfrm6_ipcomp_rcv,
212 	.err_handler	=	xfrm6_ipcomp_err,
213 	.flags		=	INET6_PROTO_NOPOLICY,
214 };
215 
216 static const struct xfrm_input_afinfo xfrm6_input_afinfo = {
217 	.family		=	AF_INET6,
218 	.callback	=	xfrm6_rcv_cb,
219 };
220 
netproto(unsigned char protocol)221 static inline const struct inet6_protocol *netproto(unsigned char protocol)
222 {
223 	switch (protocol) {
224 	case IPPROTO_ESP:
225 		return &esp6_protocol;
226 	case IPPROTO_AH:
227 		return &ah6_protocol;
228 	case IPPROTO_COMP:
229 		return &ipcomp6_protocol;
230 	}
231 
232 	return NULL;
233 }
234 
xfrm6_protocol_register(struct xfrm6_protocol * handler,unsigned char protocol)235 int xfrm6_protocol_register(struct xfrm6_protocol *handler,
236 			    unsigned char protocol)
237 {
238 	struct xfrm6_protocol __rcu **pprev;
239 	struct xfrm6_protocol *t;
240 	bool add_netproto = false;
241 	int ret = -EEXIST;
242 	int priority = handler->priority;
243 
244 	if (!proto_handlers(protocol) || !netproto(protocol))
245 		return -EINVAL;
246 
247 	mutex_lock(&xfrm6_protocol_mutex);
248 
249 	if (!rcu_dereference_protected(*proto_handlers(protocol),
250 				       lockdep_is_held(&xfrm6_protocol_mutex)))
251 		add_netproto = true;
252 
253 	for (pprev = proto_handlers(protocol);
254 	     (t = rcu_dereference_protected(*pprev,
255 			lockdep_is_held(&xfrm6_protocol_mutex))) != NULL;
256 	     pprev = &t->next) {
257 		if (t->priority < priority)
258 			break;
259 		if (t->priority == priority)
260 			goto err;
261 	}
262 
263 	handler->next = *pprev;
264 	rcu_assign_pointer(*pprev, handler);
265 
266 	ret = 0;
267 
268 err:
269 	mutex_unlock(&xfrm6_protocol_mutex);
270 
271 	if (add_netproto) {
272 		if (inet6_add_protocol(netproto(protocol), protocol)) {
273 			pr_err("%s: can't add protocol\n", __func__);
274 			ret = -EAGAIN;
275 		}
276 	}
277 
278 	return ret;
279 }
280 EXPORT_SYMBOL(xfrm6_protocol_register);
281 
xfrm6_protocol_deregister(struct xfrm6_protocol * handler,unsigned char protocol)282 int xfrm6_protocol_deregister(struct xfrm6_protocol *handler,
283 			      unsigned char protocol)
284 {
285 	struct xfrm6_protocol __rcu **pprev;
286 	struct xfrm6_protocol *t;
287 	int ret = -ENOENT;
288 
289 	if (!proto_handlers(protocol) || !netproto(protocol))
290 		return -EINVAL;
291 
292 	mutex_lock(&xfrm6_protocol_mutex);
293 
294 	for (pprev = proto_handlers(protocol);
295 	     (t = rcu_dereference_protected(*pprev,
296 			lockdep_is_held(&xfrm6_protocol_mutex))) != NULL;
297 	     pprev = &t->next) {
298 		if (t == handler) {
299 			*pprev = handler->next;
300 			ret = 0;
301 			break;
302 		}
303 	}
304 
305 	if (!rcu_dereference_protected(*proto_handlers(protocol),
306 				       lockdep_is_held(&xfrm6_protocol_mutex))) {
307 		if (inet6_del_protocol(netproto(protocol), protocol) < 0) {
308 			pr_err("%s: can't remove protocol\n", __func__);
309 			ret = -EAGAIN;
310 		}
311 	}
312 
313 	mutex_unlock(&xfrm6_protocol_mutex);
314 
315 	synchronize_net();
316 
317 	return ret;
318 }
319 EXPORT_SYMBOL(xfrm6_protocol_deregister);
320 
xfrm6_protocol_init(void)321 int __init xfrm6_protocol_init(void)
322 {
323 	return xfrm_input_register_afinfo(&xfrm6_input_afinfo);
324 }
325 
xfrm6_protocol_fini(void)326 void xfrm6_protocol_fini(void)
327 {
328 	xfrm_input_unregister_afinfo(&xfrm6_input_afinfo);
329 }
330