Blame view

net/ipv4/tunnel4.c 6.55 KB
09c434b8a   Thomas Gleixner   treewide: Add SPD...
1
  // SPDX-License-Identifier: GPL-2.0-only
d2acc3479   Herbert Xu   [INET]: Introduce...
2
3
4
5
6
7
8
9
  /* tunnel4.c: Generic IP tunnel transformer.
   *
   * Copyright (C) 2003 David S. Miller (davem@redhat.com)
   */
  
  #include <linux/init.h>
  #include <linux/module.h>
  #include <linux/mutex.h>
8afe97e5d   Simon Horman   tunnels: support ...
10
  #include <linux/mpls.h>
d2acc3479   Herbert Xu   [INET]: Introduce...
11
12
  #include <linux/netdevice.h>
  #include <linux/skbuff.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
13
  #include <linux/slab.h>
50fba2aa7   Herbert Xu   [INET]: Move no-t...
14
15
  #include <net/icmp.h>
  #include <net/ip.h>
d2acc3479   Herbert Xu   [INET]: Introduce...
16
17
  #include <net/protocol.h>
  #include <net/xfrm.h>
b33eab084   Eric Dumazet   tunnels: add __rc...
18
19
  static struct xfrm_tunnel __rcu *tunnel4_handlers __read_mostly;
  static struct xfrm_tunnel __rcu *tunnel64_handlers __read_mostly;
8afe97e5d   Simon Horman   tunnels: support ...
20
  static struct xfrm_tunnel __rcu *tunnelmpls4_handlers __read_mostly;
d2acc3479   Herbert Xu   [INET]: Introduce...
21
  static DEFINE_MUTEX(tunnel4_mutex);
b33eab084   Eric Dumazet   tunnels: add __rc...
22
  static inline struct xfrm_tunnel __rcu **fam_handlers(unsigned short family)
358352b8b   Pavel Emelyanov   [INET]: Cleanup t...
23
  {
8afe97e5d   Simon Horman   tunnels: support ...
24
25
26
  	return (family == AF_INET) ? &tunnel4_handlers :
  		(family == AF_INET6) ? &tunnel64_handlers :
  		&tunnelmpls4_handlers;
358352b8b   Pavel Emelyanov   [INET]: Cleanup t...
27
  }
c0d56408e   Kazunori MIYAZAWA   [IPSEC]: Changing...
28
  int xfrm4_tunnel_register(struct xfrm_tunnel *handler, unsigned short family)
d2acc3479   Herbert Xu   [INET]: Introduce...
29
  {
b33eab084   Eric Dumazet   tunnels: add __rc...
30
31
  	struct xfrm_tunnel __rcu **pprev;
  	struct xfrm_tunnel *t;
d2acc3479   Herbert Xu   [INET]: Introduce...
32
33
34
35
  	int ret = -EEXIST;
  	int priority = handler->priority;
  
  	mutex_lock(&tunnel4_mutex);
b33eab084   Eric Dumazet   tunnels: add __rc...
36
37
38
39
40
  	for (pprev = fam_handlers(family);
  	     (t = rcu_dereference_protected(*pprev,
  			lockdep_is_held(&tunnel4_mutex))) != NULL;
  	     pprev = &t->next) {
  		if (t->priority > priority)
d2acc3479   Herbert Xu   [INET]: Introduce...
41
  			break;
b33eab084   Eric Dumazet   tunnels: add __rc...
42
  		if (t->priority == priority)
d2acc3479   Herbert Xu   [INET]: Introduce...
43
44
45
46
  			goto err;
  	}
  
  	handler->next = *pprev;
49d61e239   Eric Dumazet   tunnels: missing ...
47
  	rcu_assign_pointer(*pprev, handler);
d2acc3479   Herbert Xu   [INET]: Introduce...
48
49
50
51
52
53
54
55
  
  	ret = 0;
  
  err:
  	mutex_unlock(&tunnel4_mutex);
  
  	return ret;
  }
d2acc3479   Herbert Xu   [INET]: Introduce...
56
  EXPORT_SYMBOL(xfrm4_tunnel_register);
c0d56408e   Kazunori MIYAZAWA   [IPSEC]: Changing...
57
  int xfrm4_tunnel_deregister(struct xfrm_tunnel *handler, unsigned short family)
d2acc3479   Herbert Xu   [INET]: Introduce...
58
  {
b33eab084   Eric Dumazet   tunnels: add __rc...
59
60
  	struct xfrm_tunnel __rcu **pprev;
  	struct xfrm_tunnel *t;
d2acc3479   Herbert Xu   [INET]: Introduce...
61
62
63
  	int ret = -ENOENT;
  
  	mutex_lock(&tunnel4_mutex);
b33eab084   Eric Dumazet   tunnels: add __rc...
64
65
66
67
68
  	for (pprev = fam_handlers(family);
  	     (t = rcu_dereference_protected(*pprev,
  			lockdep_is_held(&tunnel4_mutex))) != NULL;
  	     pprev = &t->next) {
  		if (t == handler) {
d2acc3479   Herbert Xu   [INET]: Introduce...
69
70
71
72
73
74
75
76
77
78
79
80
  			*pprev = handler->next;
  			ret = 0;
  			break;
  		}
  	}
  
  	mutex_unlock(&tunnel4_mutex);
  
  	synchronize_net();
  
  	return ret;
  }
d2acc3479   Herbert Xu   [INET]: Introduce...
81
  EXPORT_SYMBOL(xfrm4_tunnel_deregister);
875168a93   Eric Dumazet   net: tunnels shou...
82
83
84
85
  #define for_each_tunnel_rcu(head, handler)		\
  	for (handler = rcu_dereference(head);		\
  	     handler != NULL;				\
  	     handler = rcu_dereference(handler->next))	\
82695b30f   Stephen Hemminger   inet: whitespace ...
86

d2acc3479   Herbert Xu   [INET]: Introduce...
87
88
89
  static int tunnel4_rcv(struct sk_buff *skb)
  {
  	struct xfrm_tunnel *handler;
50fba2aa7   Herbert Xu   [INET]: Move no-t...
90
91
  	if (!pskb_may_pull(skb, sizeof(struct iphdr)))
  		goto drop;
875168a93   Eric Dumazet   net: tunnels shou...
92
  	for_each_tunnel_rcu(tunnel4_handlers, handler)
d2acc3479   Herbert Xu   [INET]: Introduce...
93
94
  		if (!handler->handler(skb))
  			return 0;
50fba2aa7   Herbert Xu   [INET]: Move no-t...
95
96
97
  	icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0);
  
  drop:
d2acc3479   Herbert Xu   [INET]: Introduce...
98
99
100
  	kfree_skb(skb);
  	return 0;
  }
6df2db5d3   Xin Long   tunnel4: add cb_h...
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
  #if IS_ENABLED(CONFIG_INET_XFRM_TUNNEL)
  static int tunnel4_rcv_cb(struct sk_buff *skb, u8 proto, int err)
  {
  	struct xfrm_tunnel __rcu *head;
  	struct xfrm_tunnel *handler;
  	int ret;
  
  	head = (proto == IPPROTO_IPIP) ? tunnel4_handlers : tunnel64_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 tunnel4_input_afinfo = {
  	.family		=	AF_INET,
  	.is_ipip	=	true,
  	.callback	=	tunnel4_rcv_cb,
  };
  #endif
dfd56b8b3   Eric Dumazet   net: use IS_ENABL...
127
  #if IS_ENABLED(CONFIG_IPV6)
c0d56408e   Kazunori MIYAZAWA   [IPSEC]: Changing...
128
129
130
  static int tunnel64_rcv(struct sk_buff *skb)
  {
  	struct xfrm_tunnel *handler;
baa2bfb8a   YOSHIFUJI Hideaki   [IPV4] TUNNEL4: F...
131
  	if (!pskb_may_pull(skb, sizeof(struct ipv6hdr)))
c0d56408e   Kazunori MIYAZAWA   [IPSEC]: Changing...
132
  		goto drop;
875168a93   Eric Dumazet   net: tunnels shou...
133
  	for_each_tunnel_rcu(tunnel64_handlers, handler)
c0d56408e   Kazunori MIYAZAWA   [IPSEC]: Changing...
134
135
136
137
138
139
140
141
142
143
  		if (!handler->handler(skb))
  			return 0;
  
  	icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0);
  
  drop:
  	kfree_skb(skb);
  	return 0;
  }
  #endif
8afe97e5d   Simon Horman   tunnels: support ...
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
  #if IS_ENABLED(CONFIG_MPLS)
  static int tunnelmpls4_rcv(struct sk_buff *skb)
  {
  	struct xfrm_tunnel *handler;
  
  	if (!pskb_may_pull(skb, sizeof(struct mpls_label)))
  		goto drop;
  
  	for_each_tunnel_rcu(tunnelmpls4_handlers, handler)
  		if (!handler->handler(skb))
  			return 0;
  
  	icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0);
  
  drop:
  	kfree_skb(skb);
  	return 0;
  }
  #endif
32bbd8793   Stefano Brivio   net: Convert prot...
163
  static int tunnel4_err(struct sk_buff *skb, u32 info)
d2acc3479   Herbert Xu   [INET]: Introduce...
164
165
  {
  	struct xfrm_tunnel *handler;
875168a93   Eric Dumazet   net: tunnels shou...
166
  	for_each_tunnel_rcu(tunnel4_handlers, handler)
d2acc3479   Herbert Xu   [INET]: Introduce...
167
  		if (!handler->err_handler(skb, info))
32bbd8793   Stefano Brivio   net: Convert prot...
168
169
170
  			return 0;
  
  	return -ENOENT;
d2acc3479   Herbert Xu   [INET]: Introduce...
171
  }
dfd56b8b3   Eric Dumazet   net: use IS_ENABL...
172
  #if IS_ENABLED(CONFIG_IPV6)
32bbd8793   Stefano Brivio   net: Convert prot...
173
  static int tunnel64_err(struct sk_buff *skb, u32 info)
99f933263   Pavel Emelyanov   [INET]: Add misse...
174
175
  {
  	struct xfrm_tunnel *handler;
875168a93   Eric Dumazet   net: tunnels shou...
176
  	for_each_tunnel_rcu(tunnel64_handlers, handler)
99f933263   Pavel Emelyanov   [INET]: Add misse...
177
  		if (!handler->err_handler(skb, info))
32bbd8793   Stefano Brivio   net: Convert prot...
178
179
180
  			return 0;
  
  	return -ENOENT;
99f933263   Pavel Emelyanov   [INET]: Add misse...
181
182
  }
  #endif
8afe97e5d   Simon Horman   tunnels: support ...
183
  #if IS_ENABLED(CONFIG_MPLS)
32bbd8793   Stefano Brivio   net: Convert prot...
184
  static int tunnelmpls4_err(struct sk_buff *skb, u32 info)
8afe97e5d   Simon Horman   tunnels: support ...
185
186
187
188
189
  {
  	struct xfrm_tunnel *handler;
  
  	for_each_tunnel_rcu(tunnelmpls4_handlers, handler)
  		if (!handler->err_handler(skb, info))
32bbd8793   Stefano Brivio   net: Convert prot...
190
191
192
  			return 0;
  
  	return -ENOENT;
8afe97e5d   Simon Horman   tunnels: support ...
193
194
  }
  #endif
32613090a   Alexey Dobriyan   net: constify str...
195
  static const struct net_protocol tunnel4_protocol = {
d2acc3479   Herbert Xu   [INET]: Introduce...
196
197
198
  	.handler	=	tunnel4_rcv,
  	.err_handler	=	tunnel4_err,
  	.no_policy	=	1,
4597a0ce0   Pavel Emelyanov   [IPIP]: Allow for...
199
  	.netns_ok	=	1,
d2acc3479   Herbert Xu   [INET]: Introduce...
200
  };
dfd56b8b3   Eric Dumazet   net: use IS_ENABL...
201
  #if IS_ENABLED(CONFIG_IPV6)
32613090a   Alexey Dobriyan   net: constify str...
202
  static const struct net_protocol tunnel64_protocol = {
c0d56408e   Kazunori MIYAZAWA   [IPSEC]: Changing...
203
  	.handler	=	tunnel64_rcv,
99f933263   Pavel Emelyanov   [INET]: Add misse...
204
  	.err_handler	=	tunnel64_err,
c0d56408e   Kazunori MIYAZAWA   [IPSEC]: Changing...
205
  	.no_policy	=	1,
b0970c428   Pavel Emelyanov   [SIT]: Allow for ...
206
  	.netns_ok	=	1,
c0d56408e   Kazunori MIYAZAWA   [IPSEC]: Changing...
207
208
  };
  #endif
8afe97e5d   Simon Horman   tunnels: support ...
209
210
211
212
213
214
215
216
  #if IS_ENABLED(CONFIG_MPLS)
  static const struct net_protocol tunnelmpls4_protocol = {
  	.handler	=	tunnelmpls4_rcv,
  	.err_handler	=	tunnelmpls4_err,
  	.no_policy	=	1,
  	.netns_ok	=	1,
  };
  #endif
d2acc3479   Herbert Xu   [INET]: Introduce...
217
218
  static int __init tunnel4_init(void)
  {
8afe97e5d   Simon Horman   tunnels: support ...
219
  	if (inet_add_protocol(&tunnel4_protocol, IPPROTO_IPIP))
aa9667e7f   Simon Horman   tunnels: correct ...
220
  		goto err;
dfd56b8b3   Eric Dumazet   net: use IS_ENABL...
221
  #if IS_ENABLED(CONFIG_IPV6)
aa9667e7f   Simon Horman   tunnels: correct ...
222
223
224
225
  	if (inet_add_protocol(&tunnel64_protocol, IPPROTO_IPV6)) {
  		inet_del_protocol(&tunnel4_protocol, IPPROTO_IPIP);
  		goto err;
  	}
8afe97e5d   Simon Horman   tunnels: support ...
226
227
  #endif
  #if IS_ENABLED(CONFIG_MPLS)
aa9667e7f   Simon Horman   tunnels: correct ...
228
229
230
231
232
233
234
  	if (inet_add_protocol(&tunnelmpls4_protocol, IPPROTO_MPLS)) {
  		inet_del_protocol(&tunnel4_protocol, IPPROTO_IPIP);
  #if IS_ENABLED(CONFIG_IPV6)
  		inet_del_protocol(&tunnel64_protocol, IPPROTO_IPV6);
  #endif
  		goto err;
  	}
c0d56408e   Kazunori MIYAZAWA   [IPSEC]: Changing...
235
  #endif
6df2db5d3   Xin Long   tunnel4: add cb_h...
236
237
238
239
240
241
242
243
244
245
246
247
  #if IS_ENABLED(CONFIG_INET_XFRM_TUNNEL)
  	if (xfrm_input_register_afinfo(&tunnel4_input_afinfo)) {
  		inet_del_protocol(&tunnel4_protocol, IPPROTO_IPIP);
  #if IS_ENABLED(CONFIG_IPV6)
  		inet_del_protocol(&tunnel64_protocol, IPPROTO_IPV6);
  #endif
  #if IS_ENABLED(CONFIG_MPLS)
  		inet_del_protocol(&tunnelmpls4_protocol, IPPROTO_MPLS);
  #endif
  		goto err;
  	}
  #endif
d2acc3479   Herbert Xu   [INET]: Introduce...
248
  	return 0;
8afe97e5d   Simon Horman   tunnels: support ...
249

aa9667e7f   Simon Horman   tunnels: correct ...
250
  err:
8afe97e5d   Simon Horman   tunnels: support ...
251
252
253
  	pr_err("%s: can't add protocol
  ", __func__);
  	return -EAGAIN;
d2acc3479   Herbert Xu   [INET]: Introduce...
254
255
256
257
  }
  
  static void __exit tunnel4_fini(void)
  {
6df2db5d3   Xin Long   tunnel4: add cb_h...
258
259
260
261
262
  #if IS_ENABLED(CONFIG_INET_XFRM_TUNNEL)
  	if (xfrm_input_unregister_afinfo(&tunnel4_input_afinfo))
  		pr_err("tunnel4 close: can't remove input afinfo
  ");
  #endif
8afe97e5d   Simon Horman   tunnels: support ...
263
264
265
266
267
  #if IS_ENABLED(CONFIG_MPLS)
  	if (inet_del_protocol(&tunnelmpls4_protocol, IPPROTO_MPLS))
  		pr_err("tunnelmpls4 close: can't remove protocol
  ");
  #endif
dfd56b8b3   Eric Dumazet   net: use IS_ENABL...
268
  #if IS_ENABLED(CONFIG_IPV6)
c0d56408e   Kazunori MIYAZAWA   [IPSEC]: Changing...
269
  	if (inet_del_protocol(&tunnel64_protocol, IPPROTO_IPV6))
058bd4d2a   Joe Perches   net: Convert prin...
270
271
  		pr_err("tunnel64 close: can't remove protocol
  ");
c0d56408e   Kazunori MIYAZAWA   [IPSEC]: Changing...
272
  #endif
d2acc3479   Herbert Xu   [INET]: Introduce...
273
  	if (inet_del_protocol(&tunnel4_protocol, IPPROTO_IPIP))
058bd4d2a   Joe Perches   net: Convert prin...
274
275
  		pr_err("tunnel4 close: can't remove protocol
  ");
d2acc3479   Herbert Xu   [INET]: Introduce...
276
277
278
279
280
  }
  
  module_init(tunnel4_init);
  module_exit(tunnel4_fini);
  MODULE_LICENSE("GPL");