Blame view

net/ipv6/tunnel6.c 7.05 KB
1ccea77e2   Thomas Gleixner   treewide: Replace...
1
  // SPDX-License-Identifier: GPL-2.0-or-later
d2acc3479   Herbert Xu   [INET]: Introduce...
2
3
4
  /*
   * Copyright (C)2003,2004 USAGI/WIDE Project
   *
d2acc3479   Herbert Xu   [INET]: Introduce...
5
   * Authors	Mitsuru KANDA  <mk@linux-ipv6.org>
67ba4152e   Ian Morris   ipv6: White-space...
6
   *		YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
d2acc3479   Herbert Xu   [INET]: Introduce...
7
   */
f32138319   Joe Perches   net: ipv6: Standa...
8
  #define pr_fmt(fmt) "IPv6: " fmt
50fba2aa7   Herbert Xu   [INET]: Move no-t...
9
  #include <linux/icmpv6.h>
d2acc3479   Herbert Xu   [INET]: Introduce...
10
11
12
13
14
  #include <linux/init.h>
  #include <linux/module.h>
  #include <linux/mutex.h>
  #include <linux/netdevice.h>
  #include <linux/skbuff.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
15
  #include <linux/slab.h>
50fba2aa7   Herbert Xu   [INET]: Move no-t...
16
  #include <net/ipv6.h>
d2acc3479   Herbert Xu   [INET]: Introduce...
17
18
  #include <net/protocol.h>
  #include <net/xfrm.h>
6f0bcf152   Eric Dumazet   tunnels: add _rcu...
19
20
  static struct xfrm6_tunnel __rcu *tunnel6_handlers __read_mostly;
  static struct xfrm6_tunnel __rcu *tunnel46_handlers __read_mostly;
f234efac2   Vadim Fedorenko   tunnel6: support ...
21
  static struct xfrm6_tunnel __rcu *tunnelmpls6_handlers __read_mostly;
d2acc3479   Herbert Xu   [INET]: Introduce...
22
  static DEFINE_MUTEX(tunnel6_mutex);
f234efac2   Vadim Fedorenko   tunnel6: support ...
23
24
25
26
  static inline int xfrm6_tunnel_mpls_supported(void)
  {
  	return IS_ENABLED(CONFIG_MPLS);
  }
73d605d1a   Kazunori MIYAZAWA   [IPSEC]: changing...
27
  int xfrm6_tunnel_register(struct xfrm6_tunnel *handler, unsigned short family)
d2acc3479   Herbert Xu   [INET]: Introduce...
28
  {
6f0bcf152   Eric Dumazet   tunnels: add _rcu...
29
30
  	struct xfrm6_tunnel __rcu **pprev;
  	struct xfrm6_tunnel *t;
d2acc3479   Herbert Xu   [INET]: Introduce...
31
32
33
34
  	int ret = -EEXIST;
  	int priority = handler->priority;
  
  	mutex_lock(&tunnel6_mutex);
f234efac2   Vadim Fedorenko   tunnel6: support ...
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
  	switch (family) {
  	case AF_INET6:
  		pprev = &tunnel6_handlers;
  		break;
  	case AF_INET:
  		pprev = &tunnel46_handlers;
  		break;
  	case AF_MPLS:
  		pprev = &tunnelmpls6_handlers;
  		break;
  	default:
  		goto err;
  	}
  
  	for (; (t = rcu_dereference_protected(*pprev,
6f0bcf152   Eric Dumazet   tunnels: add _rcu...
50
51
52
  			lockdep_is_held(&tunnel6_mutex))) != NULL;
  	     pprev = &t->next) {
  		if (t->priority > priority)
d2acc3479   Herbert Xu   [INET]: Introduce...
53
  			break;
6f0bcf152   Eric Dumazet   tunnels: add _rcu...
54
  		if (t->priority == priority)
d2acc3479   Herbert Xu   [INET]: Introduce...
55
56
57
58
  			goto err;
  	}
  
  	handler->next = *pprev;
49d61e239   Eric Dumazet   tunnels: missing ...
59
  	rcu_assign_pointer(*pprev, handler);
d2acc3479   Herbert Xu   [INET]: Introduce...
60
61
62
63
64
65
66
67
  
  	ret = 0;
  
  err:
  	mutex_unlock(&tunnel6_mutex);
  
  	return ret;
  }
d2acc3479   Herbert Xu   [INET]: Introduce...
68
  EXPORT_SYMBOL(xfrm6_tunnel_register);
73d605d1a   Kazunori MIYAZAWA   [IPSEC]: changing...
69
  int xfrm6_tunnel_deregister(struct xfrm6_tunnel *handler, unsigned short family)
d2acc3479   Herbert Xu   [INET]: Introduce...
70
  {
6f0bcf152   Eric Dumazet   tunnels: add _rcu...
71
72
  	struct xfrm6_tunnel __rcu **pprev;
  	struct xfrm6_tunnel *t;
d2acc3479   Herbert Xu   [INET]: Introduce...
73
74
75
  	int ret = -ENOENT;
  
  	mutex_lock(&tunnel6_mutex);
f234efac2   Vadim Fedorenko   tunnel6: support ...
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
  	switch (family) {
  	case AF_INET6:
  		pprev = &tunnel6_handlers;
  		break;
  	case AF_INET:
  		pprev = &tunnel46_handlers;
  		break;
  	case AF_MPLS:
  		pprev = &tunnelmpls6_handlers;
  		break;
  	default:
  		goto err;
  	}
  
  	for (; (t = rcu_dereference_protected(*pprev,
6f0bcf152   Eric Dumazet   tunnels: add _rcu...
91
92
93
  			lockdep_is_held(&tunnel6_mutex))) != NULL;
  	     pprev = &t->next) {
  		if (t == handler) {
d2acc3479   Herbert Xu   [INET]: Introduce...
94
95
96
97
98
  			*pprev = handler->next;
  			ret = 0;
  			break;
  		}
  	}
f234efac2   Vadim Fedorenko   tunnel6: support ...
99
  err:
d2acc3479   Herbert Xu   [INET]: Introduce...
100
101
102
103
104
105
  	mutex_unlock(&tunnel6_mutex);
  
  	synchronize_net();
  
  	return ret;
  }
d2acc3479   Herbert Xu   [INET]: Introduce...
106
  EXPORT_SYMBOL(xfrm6_tunnel_deregister);
875168a93   Eric Dumazet   net: tunnels shou...
107
108
109
110
  #define for_each_tunnel_rcu(head, handler)		\
  	for (handler = rcu_dereference(head);		\
  	     handler != NULL;				\
  	     handler = rcu_dereference(handler->next))	\
f234efac2   Vadim Fedorenko   tunnel6: support ...
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
  static int tunnelmpls6_rcv(struct sk_buff *skb)
  {
  	struct xfrm6_tunnel *handler;
  
  	if (!pskb_may_pull(skb, sizeof(struct ipv6hdr)))
  		goto drop;
  
  	for_each_tunnel_rcu(tunnelmpls6_handlers, handler)
  		if (!handler->handler(skb))
  			return 0;
  
  	icmpv6_send(skb, ICMPV6_DEST_UNREACH, ICMPV6_PORT_UNREACH, 0);
  
  drop:
  	kfree_skb(skb);
  	return 0;
  }
e5bbef20e   Herbert Xu   [IPV6]: Replace s...
128
  static int tunnel6_rcv(struct sk_buff *skb)
d2acc3479   Herbert Xu   [INET]: Introduce...
129
  {
d2acc3479   Herbert Xu   [INET]: Introduce...
130
  	struct xfrm6_tunnel *handler;
50fba2aa7   Herbert Xu   [INET]: Move no-t...
131
132
  	if (!pskb_may_pull(skb, sizeof(struct ipv6hdr)))
  		goto drop;
875168a93   Eric Dumazet   net: tunnels shou...
133
  	for_each_tunnel_rcu(tunnel6_handlers, handler)
d2acc3479   Herbert Xu   [INET]: Introduce...
134
135
  		if (!handler->handler(skb))
  			return 0;
3ffe533c8   Alexey Dobriyan   ipv6: drop unused...
136
  	icmpv6_send(skb, ICMPV6_DEST_UNREACH, ICMPV6_PORT_UNREACH, 0);
50fba2aa7   Herbert Xu   [INET]: Move no-t...
137
138
  
  drop:
d2acc3479   Herbert Xu   [INET]: Introduce...
139
140
141
  	kfree_skb(skb);
  	return 0;
  }
86afc7031   Xin Long   tunnel6: add tunn...
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
  #if IS_ENABLED(CONFIG_INET6_XFRM_TUNNEL)
  static int tunnel6_rcv_cb(struct sk_buff *skb, u8 proto, int err)
  {
  	struct xfrm6_tunnel __rcu *head;
  	struct xfrm6_tunnel *handler;
  	int ret;
  
  	head = (proto == IPPROTO_IPV6) ? tunnel6_handlers : tunnel46_handlers;
  
  	for_each_tunnel_rcu(head, handler) {
  		if (handler->cb_handler) {
  			ret = handler->cb_handler(skb, err);
  			if (ret <= 0)
  				return ret;
  		}
  	}
  
  	return 0;
  }
  
  static const struct xfrm_input_afinfo tunnel6_input_afinfo = {
  	.family		=	AF_INET6,
  	.is_ipip	=	true,
  	.callback	=	tunnel6_rcv_cb,
  };
  #endif
e5bbef20e   Herbert Xu   [IPV6]: Replace s...
168
  static int tunnel46_rcv(struct sk_buff *skb)
73d605d1a   Kazunori MIYAZAWA   [IPSEC]: changing...
169
  {
73d605d1a   Kazunori MIYAZAWA   [IPSEC]: changing...
170
  	struct xfrm6_tunnel *handler;
828363723   Colin   [IPV6] TUNNEL6: F...
171
  	if (!pskb_may_pull(skb, sizeof(struct iphdr)))
73d605d1a   Kazunori MIYAZAWA   [IPSEC]: changing...
172
  		goto drop;
875168a93   Eric Dumazet   net: tunnels shou...
173
  	for_each_tunnel_rcu(tunnel46_handlers, handler)
73d605d1a   Kazunori MIYAZAWA   [IPSEC]: changing...
174
175
  		if (!handler->handler(skb))
  			return 0;
3ffe533c8   Alexey Dobriyan   ipv6: drop unused...
176
  	icmpv6_send(skb, ICMPV6_DEST_UNREACH, ICMPV6_PORT_UNREACH, 0);
73d605d1a   Kazunori MIYAZAWA   [IPSEC]: changing...
177
178
179
180
181
  
  drop:
  	kfree_skb(skb);
  	return 0;
  }
32bbd8793   Stefano Brivio   net: Convert prot...
182
  static int tunnel6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
d5fdd6bab   Brian Haley   ipv6: Use correct...
183
  			u8 type, u8 code, int offset, __be32 info)
d2acc3479   Herbert Xu   [INET]: Introduce...
184
185
  {
  	struct xfrm6_tunnel *handler;
875168a93   Eric Dumazet   net: tunnels shou...
186
  	for_each_tunnel_rcu(tunnel6_handlers, handler)
d2acc3479   Herbert Xu   [INET]: Introduce...
187
  		if (!handler->err_handler(skb, opt, type, code, offset, info))
32bbd8793   Stefano Brivio   net: Convert prot...
188
189
190
  			return 0;
  
  	return -ENOENT;
d2acc3479   Herbert Xu   [INET]: Introduce...
191
  }
32bbd8793   Stefano Brivio   net: Convert prot...
192
  static int tunnel46_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
ebac62fe3   Michal Kubeček   ipv6: fix tunnel ...
193
194
195
196
197
198
  			 u8 type, u8 code, int offset, __be32 info)
  {
  	struct xfrm6_tunnel *handler;
  
  	for_each_tunnel_rcu(tunnel46_handlers, handler)
  		if (!handler->err_handler(skb, opt, type, code, offset, info))
32bbd8793   Stefano Brivio   net: Convert prot...
199
200
201
  			return 0;
  
  	return -ENOENT;
ebac62fe3   Michal Kubeček   ipv6: fix tunnel ...
202
  }
f234efac2   Vadim Fedorenko   tunnel6: support ...
203
204
205
206
207
208
209
210
211
212
213
  static int tunnelmpls6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
  			   u8 type, u8 code, int offset, __be32 info)
  {
  	struct xfrm6_tunnel *handler;
  
  	for_each_tunnel_rcu(tunnelmpls6_handlers, handler)
  		if (!handler->err_handler(skb, opt, type, code, offset, info))
  			return 0;
  
  	return -ENOENT;
  }
41135cc83   Alexey Dobriyan   net: constify str...
214
  static const struct inet6_protocol tunnel6_protocol = {
d2acc3479   Herbert Xu   [INET]: Introduce...
215
216
217
218
  	.handler	= tunnel6_rcv,
  	.err_handler	= tunnel6_err,
  	.flags          = INET6_PROTO_NOPOLICY|INET6_PROTO_FINAL,
  };
41135cc83   Alexey Dobriyan   net: constify str...
219
  static const struct inet6_protocol tunnel46_protocol = {
73d605d1a   Kazunori MIYAZAWA   [IPSEC]: changing...
220
  	.handler	= tunnel46_rcv,
ebac62fe3   Michal Kubeček   ipv6: fix tunnel ...
221
  	.err_handler	= tunnel46_err,
73d605d1a   Kazunori MIYAZAWA   [IPSEC]: changing...
222
223
  	.flags          = INET6_PROTO_NOPOLICY|INET6_PROTO_FINAL,
  };
f234efac2   Vadim Fedorenko   tunnel6: support ...
224
225
226
227
228
  static const struct inet6_protocol tunnelmpls6_protocol = {
  	.handler	= tunnelmpls6_rcv,
  	.err_handler	= tunnelmpls6_err,
  	.flags          = INET6_PROTO_NOPOLICY|INET6_PROTO_FINAL,
  };
d2acc3479   Herbert Xu   [INET]: Introduce...
229
230
231
  static int __init tunnel6_init(void)
  {
  	if (inet6_add_protocol(&tunnel6_protocol, IPPROTO_IPV6)) {
f32138319   Joe Perches   net: ipv6: Standa...
232
233
  		pr_err("%s: can't add protocol
  ", __func__);
d2acc3479   Herbert Xu   [INET]: Introduce...
234
235
  		return -EAGAIN;
  	}
73d605d1a   Kazunori MIYAZAWA   [IPSEC]: changing...
236
  	if (inet6_add_protocol(&tunnel46_protocol, IPPROTO_IPIP)) {
f32138319   Joe Perches   net: ipv6: Standa...
237
238
  		pr_err("%s: can't add protocol
  ", __func__);
73d605d1a   Kazunori MIYAZAWA   [IPSEC]: changing...
239
240
241
  		inet6_del_protocol(&tunnel6_protocol, IPPROTO_IPV6);
  		return -EAGAIN;
  	}
f234efac2   Vadim Fedorenko   tunnel6: support ...
242
243
244
245
246
247
248
249
  	if (xfrm6_tunnel_mpls_supported() &&
  	    inet6_add_protocol(&tunnelmpls6_protocol, IPPROTO_MPLS)) {
  		pr_err("%s: can't add protocol
  ", __func__);
  		inet6_del_protocol(&tunnel6_protocol, IPPROTO_IPV6);
  		inet6_del_protocol(&tunnel46_protocol, IPPROTO_IPIP);
  		return -EAGAIN;
  	}
86afc7031   Xin Long   tunnel6: add tunn...
250
251
252
253
254
255
256
257
258
259
260
  #if IS_ENABLED(CONFIG_INET6_XFRM_TUNNEL)
  	if (xfrm_input_register_afinfo(&tunnel6_input_afinfo)) {
  		pr_err("%s: can't add input afinfo
  ", __func__);
  		inet6_del_protocol(&tunnel6_protocol, IPPROTO_IPV6);
  		inet6_del_protocol(&tunnel46_protocol, IPPROTO_IPIP);
  		if (xfrm6_tunnel_mpls_supported())
  			inet6_del_protocol(&tunnelmpls6_protocol, IPPROTO_MPLS);
  		return -EAGAIN;
  	}
  #endif
d2acc3479   Herbert Xu   [INET]: Introduce...
261
262
263
264
265
  	return 0;
  }
  
  static void __exit tunnel6_fini(void)
  {
86afc7031   Xin Long   tunnel6: add tunn...
266
267
268
269
270
  #if IS_ENABLED(CONFIG_INET6_XFRM_TUNNEL)
  	if (xfrm_input_unregister_afinfo(&tunnel6_input_afinfo))
  		pr_err("%s: can't remove input afinfo
  ", __func__);
  #endif
73d605d1a   Kazunori MIYAZAWA   [IPSEC]: changing...
271
  	if (inet6_del_protocol(&tunnel46_protocol, IPPROTO_IPIP))
f32138319   Joe Perches   net: ipv6: Standa...
272
273
  		pr_err("%s: can't remove protocol
  ", __func__);
d2acc3479   Herbert Xu   [INET]: Introduce...
274
  	if (inet6_del_protocol(&tunnel6_protocol, IPPROTO_IPV6))
f32138319   Joe Perches   net: ipv6: Standa...
275
276
  		pr_err("%s: can't remove protocol
  ", __func__);
f234efac2   Vadim Fedorenko   tunnel6: support ...
277
278
279
280
  	if (xfrm6_tunnel_mpls_supported() &&
  	    inet6_del_protocol(&tunnelmpls6_protocol, IPPROTO_MPLS))
  		pr_err("%s: can't remove protocol
  ", __func__);
d2acc3479   Herbert Xu   [INET]: Introduce...
281
282
283
284
285
  }
  
  module_init(tunnel6_init);
  module_exit(tunnel6_fini);
  MODULE_LICENSE("GPL");