1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* tunnel4.c: Generic IP tunnel transformer. |
3 | * |
4 | * Copyright (C) 2003 David S. Miller (davem@redhat.com) |
5 | */ |
6 | |
7 | #include <linux/init.h> |
8 | #include <linux/module.h> |
9 | #include <linux/mutex.h> |
10 | #include <linux/mpls.h> |
11 | #include <linux/netdevice.h> |
12 | #include <linux/skbuff.h> |
13 | #include <linux/slab.h> |
14 | #include <net/icmp.h> |
15 | #include <net/ip.h> |
16 | #include <net/protocol.h> |
17 | #include <net/xfrm.h> |
18 | |
19 | static struct xfrm_tunnel __rcu *tunnel4_handlers __read_mostly; |
20 | static struct xfrm_tunnel __rcu *tunnel64_handlers __read_mostly; |
21 | static struct xfrm_tunnel __rcu *tunnelmpls4_handlers __read_mostly; |
22 | static DEFINE_MUTEX(tunnel4_mutex); |
23 | |
24 | static inline struct xfrm_tunnel __rcu **fam_handlers(unsigned short family) |
25 | { |
26 | return (family == AF_INET) ? &tunnel4_handlers : |
27 | (family == AF_INET6) ? &tunnel64_handlers : |
28 | &tunnelmpls4_handlers; |
29 | } |
30 | |
31 | int xfrm4_tunnel_register(struct xfrm_tunnel *handler, unsigned short family) |
32 | { |
33 | struct xfrm_tunnel __rcu **pprev; |
34 | struct xfrm_tunnel *t; |
35 | |
36 | int ret = -EEXIST; |
37 | int priority = handler->priority; |
38 | |
39 | mutex_lock(&tunnel4_mutex); |
40 | |
41 | for (pprev = fam_handlers(family); |
42 | (t = rcu_dereference_protected(*pprev, |
43 | lockdep_is_held(&tunnel4_mutex))) != NULL; |
44 | pprev = &t->next) { |
45 | if (t->priority > priority) |
46 | break; |
47 | if (t->priority == priority) |
48 | goto err; |
49 | } |
50 | |
51 | handler->next = *pprev; |
52 | rcu_assign_pointer(*pprev, handler); |
53 | |
54 | ret = 0; |
55 | |
56 | err: |
57 | mutex_unlock(lock: &tunnel4_mutex); |
58 | |
59 | return ret; |
60 | } |
61 | EXPORT_SYMBOL(xfrm4_tunnel_register); |
62 | |
63 | int xfrm4_tunnel_deregister(struct xfrm_tunnel *handler, unsigned short family) |
64 | { |
65 | struct xfrm_tunnel __rcu **pprev; |
66 | struct xfrm_tunnel *t; |
67 | int ret = -ENOENT; |
68 | |
69 | mutex_lock(&tunnel4_mutex); |
70 | |
71 | for (pprev = fam_handlers(family); |
72 | (t = rcu_dereference_protected(*pprev, |
73 | lockdep_is_held(&tunnel4_mutex))) != NULL; |
74 | pprev = &t->next) { |
75 | if (t == handler) { |
76 | *pprev = handler->next; |
77 | ret = 0; |
78 | break; |
79 | } |
80 | } |
81 | |
82 | mutex_unlock(lock: &tunnel4_mutex); |
83 | |
84 | synchronize_net(); |
85 | |
86 | return ret; |
87 | } |
88 | EXPORT_SYMBOL(xfrm4_tunnel_deregister); |
89 | |
90 | #define for_each_tunnel_rcu(head, handler) \ |
91 | for (handler = rcu_dereference(head); \ |
92 | handler != NULL; \ |
93 | handler = rcu_dereference(handler->next)) \ |
94 | |
95 | static int tunnel4_rcv(struct sk_buff *skb) |
96 | { |
97 | struct xfrm_tunnel *handler; |
98 | |
99 | if (!pskb_may_pull(skb, len: sizeof(struct iphdr))) |
100 | goto drop; |
101 | |
102 | for_each_tunnel_rcu(tunnel4_handlers, handler) |
103 | if (!handler->handler(skb)) |
104 | return 0; |
105 | |
106 | icmp_send(skb_in: skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, info: 0); |
107 | |
108 | drop: |
109 | kfree_skb(skb); |
110 | return 0; |
111 | } |
112 | |
113 | #if IS_ENABLED(CONFIG_INET_XFRM_TUNNEL) |
114 | static int tunnel4_rcv_cb(struct sk_buff *skb, u8 proto, int err) |
115 | { |
116 | struct xfrm_tunnel __rcu *head; |
117 | struct xfrm_tunnel *handler; |
118 | int ret; |
119 | |
120 | head = (proto == IPPROTO_IPIP) ? tunnel4_handlers : tunnel64_handlers; |
121 | |
122 | for_each_tunnel_rcu(head, handler) { |
123 | if (handler->cb_handler) { |
124 | ret = handler->cb_handler(skb, err); |
125 | if (ret <= 0) |
126 | return ret; |
127 | } |
128 | } |
129 | |
130 | return 0; |
131 | } |
132 | |
133 | static const struct xfrm_input_afinfo tunnel4_input_afinfo = { |
134 | .family = AF_INET, |
135 | .is_ipip = true, |
136 | .callback = tunnel4_rcv_cb, |
137 | }; |
138 | #endif |
139 | |
140 | #if IS_ENABLED(CONFIG_IPV6) |
141 | static int tunnel64_rcv(struct sk_buff *skb) |
142 | { |
143 | struct xfrm_tunnel *handler; |
144 | |
145 | if (!pskb_may_pull(skb, len: sizeof(struct ipv6hdr))) |
146 | goto drop; |
147 | |
148 | for_each_tunnel_rcu(tunnel64_handlers, handler) |
149 | if (!handler->handler(skb)) |
150 | return 0; |
151 | |
152 | icmp_send(skb_in: skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, info: 0); |
153 | |
154 | drop: |
155 | kfree_skb(skb); |
156 | return 0; |
157 | } |
158 | #endif |
159 | |
160 | #if IS_ENABLED(CONFIG_MPLS) |
161 | static int tunnelmpls4_rcv(struct sk_buff *skb) |
162 | { |
163 | struct xfrm_tunnel *handler; |
164 | |
165 | if (!pskb_may_pull(skb, len: sizeof(struct mpls_label))) |
166 | goto drop; |
167 | |
168 | for_each_tunnel_rcu(tunnelmpls4_handlers, handler) |
169 | if (!handler->handler(skb)) |
170 | return 0; |
171 | |
172 | icmp_send(skb_in: skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, info: 0); |
173 | |
174 | drop: |
175 | kfree_skb(skb); |
176 | return 0; |
177 | } |
178 | #endif |
179 | |
180 | static int tunnel4_err(struct sk_buff *skb, u32 info) |
181 | { |
182 | struct xfrm_tunnel *handler; |
183 | |
184 | for_each_tunnel_rcu(tunnel4_handlers, handler) |
185 | if (!handler->err_handler(skb, info)) |
186 | return 0; |
187 | |
188 | return -ENOENT; |
189 | } |
190 | |
191 | #if IS_ENABLED(CONFIG_IPV6) |
192 | static int tunnel64_err(struct sk_buff *skb, u32 info) |
193 | { |
194 | struct xfrm_tunnel *handler; |
195 | |
196 | for_each_tunnel_rcu(tunnel64_handlers, handler) |
197 | if (!handler->err_handler(skb, info)) |
198 | return 0; |
199 | |
200 | return -ENOENT; |
201 | } |
202 | #endif |
203 | |
204 | #if IS_ENABLED(CONFIG_MPLS) |
205 | static int tunnelmpls4_err(struct sk_buff *skb, u32 info) |
206 | { |
207 | struct xfrm_tunnel *handler; |
208 | |
209 | for_each_tunnel_rcu(tunnelmpls4_handlers, handler) |
210 | if (!handler->err_handler(skb, info)) |
211 | return 0; |
212 | |
213 | return -ENOENT; |
214 | } |
215 | #endif |
216 | |
217 | static const struct net_protocol tunnel4_protocol = { |
218 | .handler = tunnel4_rcv, |
219 | .err_handler = tunnel4_err, |
220 | .no_policy = 1, |
221 | }; |
222 | |
223 | #if IS_ENABLED(CONFIG_IPV6) |
224 | static const struct net_protocol tunnel64_protocol = { |
225 | .handler = tunnel64_rcv, |
226 | .err_handler = tunnel64_err, |
227 | .no_policy = 1, |
228 | }; |
229 | #endif |
230 | |
231 | #if IS_ENABLED(CONFIG_MPLS) |
232 | static const struct net_protocol tunnelmpls4_protocol = { |
233 | .handler = tunnelmpls4_rcv, |
234 | .err_handler = tunnelmpls4_err, |
235 | .no_policy = 1, |
236 | }; |
237 | #endif |
238 | |
239 | static int __init tunnel4_init(void) |
240 | { |
241 | if (inet_add_protocol(prot: &tunnel4_protocol, IPPROTO_IPIP)) |
242 | goto err; |
243 | #if IS_ENABLED(CONFIG_IPV6) |
244 | if (inet_add_protocol(prot: &tunnel64_protocol, IPPROTO_IPV6)) { |
245 | inet_del_protocol(prot: &tunnel4_protocol, IPPROTO_IPIP); |
246 | goto err; |
247 | } |
248 | #endif |
249 | #if IS_ENABLED(CONFIG_MPLS) |
250 | if (inet_add_protocol(prot: &tunnelmpls4_protocol, IPPROTO_MPLS)) { |
251 | inet_del_protocol(prot: &tunnel4_protocol, IPPROTO_IPIP); |
252 | #if IS_ENABLED(CONFIG_IPV6) |
253 | inet_del_protocol(prot: &tunnel64_protocol, IPPROTO_IPV6); |
254 | #endif |
255 | goto err; |
256 | } |
257 | #endif |
258 | #if IS_ENABLED(CONFIG_INET_XFRM_TUNNEL) |
259 | if (xfrm_input_register_afinfo(afinfo: &tunnel4_input_afinfo)) { |
260 | inet_del_protocol(prot: &tunnel4_protocol, IPPROTO_IPIP); |
261 | #if IS_ENABLED(CONFIG_IPV6) |
262 | inet_del_protocol(prot: &tunnel64_protocol, IPPROTO_IPV6); |
263 | #endif |
264 | #if IS_ENABLED(CONFIG_MPLS) |
265 | inet_del_protocol(prot: &tunnelmpls4_protocol, IPPROTO_MPLS); |
266 | #endif |
267 | goto err; |
268 | } |
269 | #endif |
270 | return 0; |
271 | |
272 | err: |
273 | pr_err("%s: can't add protocol\n" , __func__); |
274 | return -EAGAIN; |
275 | } |
276 | |
277 | static void __exit tunnel4_fini(void) |
278 | { |
279 | #if IS_ENABLED(CONFIG_INET_XFRM_TUNNEL) |
280 | if (xfrm_input_unregister_afinfo(afinfo: &tunnel4_input_afinfo)) |
281 | pr_err("tunnel4 close: can't remove input afinfo\n" ); |
282 | #endif |
283 | #if IS_ENABLED(CONFIG_MPLS) |
284 | if (inet_del_protocol(prot: &tunnelmpls4_protocol, IPPROTO_MPLS)) |
285 | pr_err("tunnelmpls4 close: can't remove protocol\n" ); |
286 | #endif |
287 | #if IS_ENABLED(CONFIG_IPV6) |
288 | if (inet_del_protocol(prot: &tunnel64_protocol, IPPROTO_IPV6)) |
289 | pr_err("tunnel64 close: can't remove protocol\n" ); |
290 | #endif |
291 | if (inet_del_protocol(prot: &tunnel4_protocol, IPPROTO_IPIP)) |
292 | pr_err("tunnel4 close: can't remove protocol\n" ); |
293 | } |
294 | |
295 | module_init(tunnel4_init); |
296 | module_exit(tunnel4_fini); |
297 | MODULE_LICENSE("GPL" ); |
298 | |