Branch data Line data Source code
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 : 22 : static inline struct xfrm_tunnel __rcu **fam_handlers(unsigned short family)
25 : : {
26 : 22 : return (family == AF_INET) ? &tunnel4_handlers :
27 [ - - - + ]: 11 : (family == AF_INET6) ? &tunnel64_handlers :
28 : : &tunnelmpls4_handlers;
29 : : }
30 : :
31 : 22 : int xfrm4_tunnel_register(struct xfrm_tunnel *handler, unsigned short family)
32 : : {
33 : 22 : struct xfrm_tunnel __rcu **pprev;
34 : 22 : struct xfrm_tunnel *t;
35 : :
36 : 22 : int ret = -EEXIST;
37 : 22 : int priority = handler->priority;
38 : :
39 : 22 : mutex_lock(&tunnel4_mutex);
40 : :
41 [ + + ]: 22 : for (pprev = fam_handlers(family);
42 [ - + ]: 22 : (t = rcu_dereference_protected(*pprev,
43 : : lockdep_is_held(&tunnel4_mutex))) != NULL;
44 : 0 : pprev = &t->next) {
45 [ # # ]: 0 : if (t->priority > priority)
46 : : break;
47 [ # # ]: 0 : if (t->priority == priority)
48 : 0 : goto err;
49 : : }
50 : :
51 : 22 : handler->next = *pprev;
52 : 22 : rcu_assign_pointer(*pprev, handler);
53 : :
54 : 22 : ret = 0;
55 : :
56 : 22 : err:
57 : 22 : mutex_unlock(&tunnel4_mutex);
58 : :
59 : 22 : return ret;
60 : : }
61 : : EXPORT_SYMBOL(xfrm4_tunnel_register);
62 : :
63 : 0 : int xfrm4_tunnel_deregister(struct xfrm_tunnel *handler, unsigned short family)
64 : : {
65 : 0 : struct xfrm_tunnel __rcu **pprev;
66 : 0 : struct xfrm_tunnel *t;
67 : 0 : int ret = -ENOENT;
68 : :
69 : 0 : mutex_lock(&tunnel4_mutex);
70 : :
71 [ # # ]: 0 : for (pprev = fam_handlers(family);
72 [ # # ]: 0 : (t = rcu_dereference_protected(*pprev,
73 : : lockdep_is_held(&tunnel4_mutex))) != NULL;
74 : 0 : pprev = &t->next) {
75 [ # # ]: 0 : if (t == handler) {
76 : 0 : *pprev = handler->next;
77 : 0 : ret = 0;
78 : 0 : break;
79 : : }
80 : : }
81 : :
82 : 0 : mutex_unlock(&tunnel4_mutex);
83 : :
84 : 0 : synchronize_net();
85 : :
86 : 0 : 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 : 0 : static int tunnel4_rcv(struct sk_buff *skb)
96 : : {
97 : 0 : struct xfrm_tunnel *handler;
98 : :
99 [ # # ]: 0 : if (!pskb_may_pull(skb, sizeof(struct iphdr)))
100 : 0 : goto drop;
101 : :
102 [ # # ]: 0 : for_each_tunnel_rcu(tunnel4_handlers, handler)
103 [ # # ]: 0 : if (!handler->handler(skb))
104 : : return 0;
105 : :
106 : 0 : icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0);
107 : :
108 : 0 : drop:
109 : 0 : kfree_skb(skb);
110 : 0 : return 0;
111 : : }
112 : :
113 : : #if IS_ENABLED(CONFIG_IPV6)
114 : 0 : static int tunnel64_rcv(struct sk_buff *skb)
115 : : {
116 : 0 : struct xfrm_tunnel *handler;
117 : :
118 [ # # ]: 0 : if (!pskb_may_pull(skb, sizeof(struct ipv6hdr)))
119 : 0 : goto drop;
120 : :
121 [ # # ]: 0 : for_each_tunnel_rcu(tunnel64_handlers, handler)
122 [ # # ]: 0 : if (!handler->handler(skb))
123 : : return 0;
124 : :
125 : 0 : icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0);
126 : :
127 : 0 : drop:
128 : 0 : kfree_skb(skb);
129 : 0 : return 0;
130 : : }
131 : : #endif
132 : :
133 : : #if IS_ENABLED(CONFIG_MPLS)
134 : : static int tunnelmpls4_rcv(struct sk_buff *skb)
135 : : {
136 : : struct xfrm_tunnel *handler;
137 : :
138 : : if (!pskb_may_pull(skb, sizeof(struct mpls_label)))
139 : : goto drop;
140 : :
141 : : for_each_tunnel_rcu(tunnelmpls4_handlers, handler)
142 : : if (!handler->handler(skb))
143 : : return 0;
144 : :
145 : : icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0);
146 : :
147 : : drop:
148 : : kfree_skb(skb);
149 : : return 0;
150 : : }
151 : : #endif
152 : :
153 : 0 : static int tunnel4_err(struct sk_buff *skb, u32 info)
154 : : {
155 : 0 : struct xfrm_tunnel *handler;
156 : :
157 [ # # ]: 0 : for_each_tunnel_rcu(tunnel4_handlers, handler)
158 [ # # ]: 0 : if (!handler->err_handler(skb, info))
159 : : return 0;
160 : :
161 : : return -ENOENT;
162 : : }
163 : :
164 : : #if IS_ENABLED(CONFIG_IPV6)
165 : 0 : static int tunnel64_err(struct sk_buff *skb, u32 info)
166 : : {
167 : 0 : struct xfrm_tunnel *handler;
168 : :
169 [ # # ]: 0 : for_each_tunnel_rcu(tunnel64_handlers, handler)
170 [ # # ]: 0 : if (!handler->err_handler(skb, info))
171 : : return 0;
172 : :
173 : : return -ENOENT;
174 : : }
175 : : #endif
176 : :
177 : : #if IS_ENABLED(CONFIG_MPLS)
178 : : static int tunnelmpls4_err(struct sk_buff *skb, u32 info)
179 : : {
180 : : struct xfrm_tunnel *handler;
181 : :
182 : : for_each_tunnel_rcu(tunnelmpls4_handlers, handler)
183 : : if (!handler->err_handler(skb, info))
184 : : return 0;
185 : :
186 : : return -ENOENT;
187 : : }
188 : : #endif
189 : :
190 : : static const struct net_protocol tunnel4_protocol = {
191 : : .handler = tunnel4_rcv,
192 : : .err_handler = tunnel4_err,
193 : : .no_policy = 1,
194 : : .netns_ok = 1,
195 : : };
196 : :
197 : : #if IS_ENABLED(CONFIG_IPV6)
198 : : static const struct net_protocol tunnel64_protocol = {
199 : : .handler = tunnel64_rcv,
200 : : .err_handler = tunnel64_err,
201 : : .no_policy = 1,
202 : : .netns_ok = 1,
203 : : };
204 : : #endif
205 : :
206 : : #if IS_ENABLED(CONFIG_MPLS)
207 : : static const struct net_protocol tunnelmpls4_protocol = {
208 : : .handler = tunnelmpls4_rcv,
209 : : .err_handler = tunnelmpls4_err,
210 : : .no_policy = 1,
211 : : .netns_ok = 1,
212 : : };
213 : : #endif
214 : :
215 : 11 : static int __init tunnel4_init(void)
216 : : {
217 [ - + ]: 11 : if (inet_add_protocol(&tunnel4_protocol, IPPROTO_IPIP))
218 : 0 : goto err;
219 : : #if IS_ENABLED(CONFIG_IPV6)
220 [ - + ]: 11 : if (inet_add_protocol(&tunnel64_protocol, IPPROTO_IPV6)) {
221 : 0 : inet_del_protocol(&tunnel4_protocol, IPPROTO_IPIP);
222 : 0 : goto err;
223 : : }
224 : : #endif
225 : : #if IS_ENABLED(CONFIG_MPLS)
226 : : if (inet_add_protocol(&tunnelmpls4_protocol, IPPROTO_MPLS)) {
227 : : inet_del_protocol(&tunnel4_protocol, IPPROTO_IPIP);
228 : : #if IS_ENABLED(CONFIG_IPV6)
229 : : inet_del_protocol(&tunnel64_protocol, IPPROTO_IPV6);
230 : : #endif
231 : : goto err;
232 : : }
233 : : #endif
234 : : return 0;
235 : :
236 : 0 : err:
237 : 0 : pr_err("%s: can't add protocol\n", __func__);
238 : 0 : return -EAGAIN;
239 : : }
240 : :
241 : 0 : static void __exit tunnel4_fini(void)
242 : : {
243 : : #if IS_ENABLED(CONFIG_MPLS)
244 : : if (inet_del_protocol(&tunnelmpls4_protocol, IPPROTO_MPLS))
245 : : pr_err("tunnelmpls4 close: can't remove protocol\n");
246 : : #endif
247 : : #if IS_ENABLED(CONFIG_IPV6)
248 [ # # ]: 0 : if (inet_del_protocol(&tunnel64_protocol, IPPROTO_IPV6))
249 : 0 : pr_err("tunnel64 close: can't remove protocol\n");
250 : : #endif
251 [ # # ]: 0 : if (inet_del_protocol(&tunnel4_protocol, IPPROTO_IPIP))
252 : 0 : pr_err("tunnel4 close: can't remove protocol\n");
253 : 0 : }
254 : :
255 : : module_init(tunnel4_init);
256 : : module_exit(tunnel4_fini);
257 : : MODULE_LICENSE("GPL");
|