Linux Audio

Check our new training course

Linux BSP development engineering services

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