Linux Audio

Check our new training course

Loading...
v3.15
  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/netdevice.h>
 10#include <linux/skbuff.h>
 11#include <linux/slab.h>
 12#include <net/icmp.h>
 13#include <net/ip.h>
 14#include <net/protocol.h>
 15#include <net/xfrm.h>
 16
 17static struct xfrm_tunnel __rcu *tunnel4_handlers __read_mostly;
 18static struct xfrm_tunnel __rcu *tunnel64_handlers __read_mostly;
 
 19static DEFINE_MUTEX(tunnel4_mutex);
 20
 21static inline struct xfrm_tunnel __rcu **fam_handlers(unsigned short family)
 22{
 23	return (family == AF_INET) ? &tunnel4_handlers : &tunnel64_handlers;
 
 
 24}
 25
 26int xfrm4_tunnel_register(struct xfrm_tunnel *handler, unsigned short family)
 27{
 28	struct xfrm_tunnel __rcu **pprev;
 29	struct xfrm_tunnel *t;
 30
 31	int ret = -EEXIST;
 32	int priority = handler->priority;
 33
 34	mutex_lock(&tunnel4_mutex);
 35
 36	for (pprev = fam_handlers(family);
 37	     (t = rcu_dereference_protected(*pprev,
 38			lockdep_is_held(&tunnel4_mutex))) != NULL;
 39	     pprev = &t->next) {
 40		if (t->priority > priority)
 41			break;
 42		if (t->priority == priority)
 43			goto err;
 44	}
 45
 46	handler->next = *pprev;
 47	rcu_assign_pointer(*pprev, handler);
 48
 49	ret = 0;
 50
 51err:
 52	mutex_unlock(&tunnel4_mutex);
 53
 54	return ret;
 55}
 56EXPORT_SYMBOL(xfrm4_tunnel_register);
 57
 58int xfrm4_tunnel_deregister(struct xfrm_tunnel *handler, unsigned short family)
 59{
 60	struct xfrm_tunnel __rcu **pprev;
 61	struct xfrm_tunnel *t;
 62	int ret = -ENOENT;
 63
 64	mutex_lock(&tunnel4_mutex);
 65
 66	for (pprev = fam_handlers(family);
 67	     (t = rcu_dereference_protected(*pprev,
 68			lockdep_is_held(&tunnel4_mutex))) != NULL;
 69	     pprev = &t->next) {
 70		if (t == handler) {
 71			*pprev = handler->next;
 72			ret = 0;
 73			break;
 74		}
 75	}
 76
 77	mutex_unlock(&tunnel4_mutex);
 78
 79	synchronize_net();
 80
 81	return ret;
 82}
 83EXPORT_SYMBOL(xfrm4_tunnel_deregister);
 84
 85#define for_each_tunnel_rcu(head, handler)		\
 86	for (handler = rcu_dereference(head);		\
 87	     handler != NULL;				\
 88	     handler = rcu_dereference(handler->next))	\
 89	
 90static int tunnel4_rcv(struct sk_buff *skb)
 91{
 92	struct xfrm_tunnel *handler;
 93
 94	if (!pskb_may_pull(skb, sizeof(struct iphdr)))
 95		goto drop;
 96
 97	for_each_tunnel_rcu(tunnel4_handlers, handler)
 98		if (!handler->handler(skb))
 99			return 0;
100
101	icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0);
102
103drop:
104	kfree_skb(skb);
105	return 0;
106}
107
108#if IS_ENABLED(CONFIG_IPV6)
109static int tunnel64_rcv(struct sk_buff *skb)
110{
111	struct xfrm_tunnel *handler;
112
113	if (!pskb_may_pull(skb, sizeof(struct ipv6hdr)))
114		goto drop;
115
116	for_each_tunnel_rcu(tunnel64_handlers, handler)
117		if (!handler->handler(skb))
118			return 0;
119
120	icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0);
121
122drop:
123	kfree_skb(skb);
124	return 0;
125}
126#endif
127
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
128static void tunnel4_err(struct sk_buff *skb, u32 info)
129{
130	struct xfrm_tunnel *handler;
131
132	for_each_tunnel_rcu(tunnel4_handlers, handler)
133		if (!handler->err_handler(skb, info))
134			break;
135}
136
137#if IS_ENABLED(CONFIG_IPV6)
138static void tunnel64_err(struct sk_buff *skb, u32 info)
139{
140	struct xfrm_tunnel *handler;
141
142	for_each_tunnel_rcu(tunnel64_handlers, handler)
143		if (!handler->err_handler(skb, info))
144			break;
145}
146#endif
147
 
 
 
 
 
 
 
 
 
 
 
148static const struct net_protocol tunnel4_protocol = {
149	.handler	=	tunnel4_rcv,
150	.err_handler	=	tunnel4_err,
151	.no_policy	=	1,
152	.netns_ok	=	1,
153};
154
155#if IS_ENABLED(CONFIG_IPV6)
156static const struct net_protocol tunnel64_protocol = {
157	.handler	=	tunnel64_rcv,
158	.err_handler	=	tunnel64_err,
159	.no_policy	=	1,
160	.netns_ok	=	1,
161};
162#endif
163
 
 
 
 
 
 
 
 
 
164static int __init tunnel4_init(void)
165{
166	if (inet_add_protocol(&tunnel4_protocol, IPPROTO_IPIP)) {
167		pr_err("%s: can't add protocol\n", __func__);
168		return -EAGAIN;
169	}
170#if IS_ENABLED(CONFIG_IPV6)
171	if (inet_add_protocol(&tunnel64_protocol, IPPROTO_IPV6)) {
172		pr_err("tunnel64 init: can't add protocol\n");
173		inet_del_protocol(&tunnel4_protocol, IPPROTO_IPIP);
174		return -EAGAIN;
 
 
 
 
 
 
 
 
 
175	}
176#endif
177	return 0;
 
 
 
 
178}
179
180static void __exit tunnel4_fini(void)
181{
 
 
 
 
182#if IS_ENABLED(CONFIG_IPV6)
183	if (inet_del_protocol(&tunnel64_protocol, IPPROTO_IPV6))
184		pr_err("tunnel64 close: can't remove protocol\n");
185#endif
186	if (inet_del_protocol(&tunnel4_protocol, IPPROTO_IPIP))
187		pr_err("tunnel4 close: can't remove protocol\n");
188}
189
190module_init(tunnel4_init);
191module_exit(tunnel4_fini);
192MODULE_LICENSE("GPL");
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");