Blame view

net/ipv4/tunnel4.c 4.16 KB
d2acc3479   Herbert Xu   [INET]: Introduce...
1
2
3
4
5
6
7
8
9
10
  /* 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>
  #include <linux/netdevice.h>
  #include <linux/skbuff.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
11
  #include <linux/slab.h>
50fba2aa7   Herbert Xu   [INET]: Move no-t...
12
13
  #include <net/icmp.h>
  #include <net/ip.h>
d2acc3479   Herbert Xu   [INET]: Introduce...
14
15
  #include <net/protocol.h>
  #include <net/xfrm.h>
b33eab084   Eric Dumazet   tunnels: add __rc...
16
17
  static struct xfrm_tunnel __rcu *tunnel4_handlers __read_mostly;
  static struct xfrm_tunnel __rcu *tunnel64_handlers __read_mostly;
d2acc3479   Herbert Xu   [INET]: Introduce...
18
  static DEFINE_MUTEX(tunnel4_mutex);
b33eab084   Eric Dumazet   tunnels: add __rc...
19
  static inline struct xfrm_tunnel __rcu **fam_handlers(unsigned short family)
358352b8b   Pavel Emelyanov   [INET]: Cleanup t...
20
21
22
  {
  	return (family == AF_INET) ? &tunnel4_handlers : &tunnel64_handlers;
  }
c0d56408e   Kazunori MIYAZAWA   [IPSEC]: Changing...
23
  int xfrm4_tunnel_register(struct xfrm_tunnel *handler, unsigned short family)
d2acc3479   Herbert Xu   [INET]: Introduce...
24
  {
b33eab084   Eric Dumazet   tunnels: add __rc...
25
26
  	struct xfrm_tunnel __rcu **pprev;
  	struct xfrm_tunnel *t;
d2acc3479   Herbert Xu   [INET]: Introduce...
27
28
29
30
  	int ret = -EEXIST;
  	int priority = handler->priority;
  
  	mutex_lock(&tunnel4_mutex);
b33eab084   Eric Dumazet   tunnels: add __rc...
31
32
33
34
35
  	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...
36
  			break;
b33eab084   Eric Dumazet   tunnels: add __rc...
37
  		if (t->priority == priority)
d2acc3479   Herbert Xu   [INET]: Introduce...
38
39
40
41
  			goto err;
  	}
  
  	handler->next = *pprev;
49d61e239   Eric Dumazet   tunnels: missing ...
42
  	rcu_assign_pointer(*pprev, handler);
d2acc3479   Herbert Xu   [INET]: Introduce...
43
44
45
46
47
48
49
50
  
  	ret = 0;
  
  err:
  	mutex_unlock(&tunnel4_mutex);
  
  	return ret;
  }
d2acc3479   Herbert Xu   [INET]: Introduce...
51
  EXPORT_SYMBOL(xfrm4_tunnel_register);
c0d56408e   Kazunori MIYAZAWA   [IPSEC]: Changing...
52
  int xfrm4_tunnel_deregister(struct xfrm_tunnel *handler, unsigned short family)
d2acc3479   Herbert Xu   [INET]: Introduce...
53
  {
b33eab084   Eric Dumazet   tunnels: add __rc...
54
55
  	struct xfrm_tunnel __rcu **pprev;
  	struct xfrm_tunnel *t;
d2acc3479   Herbert Xu   [INET]: Introduce...
56
57
58
  	int ret = -ENOENT;
  
  	mutex_lock(&tunnel4_mutex);
b33eab084   Eric Dumazet   tunnels: add __rc...
59
60
61
62
63
  	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...
64
65
66
67
68
69
70
71
72
73
74
75
  			*pprev = handler->next;
  			ret = 0;
  			break;
  		}
  	}
  
  	mutex_unlock(&tunnel4_mutex);
  
  	synchronize_net();
  
  	return ret;
  }
d2acc3479   Herbert Xu   [INET]: Introduce...
76
  EXPORT_SYMBOL(xfrm4_tunnel_deregister);
875168a93   Eric Dumazet   net: tunnels shou...
77
78
79
80
81
  #define for_each_tunnel_rcu(head, handler)		\
  	for (handler = rcu_dereference(head);		\
  	     handler != NULL;				\
  	     handler = rcu_dereference(handler->next))	\
  	
d2acc3479   Herbert Xu   [INET]: Introduce...
82
83
84
  static int tunnel4_rcv(struct sk_buff *skb)
  {
  	struct xfrm_tunnel *handler;
50fba2aa7   Herbert Xu   [INET]: Move no-t...
85
86
  	if (!pskb_may_pull(skb, sizeof(struct iphdr)))
  		goto drop;
875168a93   Eric Dumazet   net: tunnels shou...
87
  	for_each_tunnel_rcu(tunnel4_handlers, handler)
d2acc3479   Herbert Xu   [INET]: Introduce...
88
89
  		if (!handler->handler(skb))
  			return 0;
50fba2aa7   Herbert Xu   [INET]: Move no-t...
90
91
92
  	icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0);
  
  drop:
d2acc3479   Herbert Xu   [INET]: Introduce...
93
94
95
  	kfree_skb(skb);
  	return 0;
  }
dfd56b8b3   Eric Dumazet   net: use IS_ENABL...
96
  #if IS_ENABLED(CONFIG_IPV6)
c0d56408e   Kazunori MIYAZAWA   [IPSEC]: Changing...
97
98
99
  static int tunnel64_rcv(struct sk_buff *skb)
  {
  	struct xfrm_tunnel *handler;
baa2bfb8a   YOSHIFUJI Hideaki   [IPV4] TUNNEL4: F...
100
  	if (!pskb_may_pull(skb, sizeof(struct ipv6hdr)))
c0d56408e   Kazunori MIYAZAWA   [IPSEC]: Changing...
101
  		goto drop;
875168a93   Eric Dumazet   net: tunnels shou...
102
  	for_each_tunnel_rcu(tunnel64_handlers, handler)
c0d56408e   Kazunori MIYAZAWA   [IPSEC]: Changing...
103
104
105
106
107
108
109
110
111
112
  		if (!handler->handler(skb))
  			return 0;
  
  	icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0);
  
  drop:
  	kfree_skb(skb);
  	return 0;
  }
  #endif
d2acc3479   Herbert Xu   [INET]: Introduce...
113
114
115
  static void tunnel4_err(struct sk_buff *skb, u32 info)
  {
  	struct xfrm_tunnel *handler;
875168a93   Eric Dumazet   net: tunnels shou...
116
  	for_each_tunnel_rcu(tunnel4_handlers, handler)
d2acc3479   Herbert Xu   [INET]: Introduce...
117
118
119
  		if (!handler->err_handler(skb, info))
  			break;
  }
dfd56b8b3   Eric Dumazet   net: use IS_ENABL...
120
  #if IS_ENABLED(CONFIG_IPV6)
99f933263   Pavel Emelyanov   [INET]: Add misse...
121
122
123
  static void tunnel64_err(struct sk_buff *skb, u32 info)
  {
  	struct xfrm_tunnel *handler;
875168a93   Eric Dumazet   net: tunnels shou...
124
  	for_each_tunnel_rcu(tunnel64_handlers, handler)
99f933263   Pavel Emelyanov   [INET]: Add misse...
125
126
127
128
  		if (!handler->err_handler(skb, info))
  			break;
  }
  #endif
32613090a   Alexey Dobriyan   net: constify str...
129
  static const struct net_protocol tunnel4_protocol = {
d2acc3479   Herbert Xu   [INET]: Introduce...
130
131
132
  	.handler	=	tunnel4_rcv,
  	.err_handler	=	tunnel4_err,
  	.no_policy	=	1,
4597a0ce0   Pavel Emelyanov   [IPIP]: Allow for...
133
  	.netns_ok	=	1,
d2acc3479   Herbert Xu   [INET]: Introduce...
134
  };
dfd56b8b3   Eric Dumazet   net: use IS_ENABL...
135
  #if IS_ENABLED(CONFIG_IPV6)
32613090a   Alexey Dobriyan   net: constify str...
136
  static const struct net_protocol tunnel64_protocol = {
c0d56408e   Kazunori MIYAZAWA   [IPSEC]: Changing...
137
  	.handler	=	tunnel64_rcv,
99f933263   Pavel Emelyanov   [INET]: Add misse...
138
  	.err_handler	=	tunnel64_err,
c0d56408e   Kazunori MIYAZAWA   [IPSEC]: Changing...
139
  	.no_policy	=	1,
b0970c428   Pavel Emelyanov   [SIT]: Allow for ...
140
  	.netns_ok	=	1,
c0d56408e   Kazunori MIYAZAWA   [IPSEC]: Changing...
141
142
  };
  #endif
d2acc3479   Herbert Xu   [INET]: Introduce...
143
144
145
146
147
148
149
  static int __init tunnel4_init(void)
  {
  	if (inet_add_protocol(&tunnel4_protocol, IPPROTO_IPIP)) {
  		printk(KERN_ERR "tunnel4 init: can't add protocol
  ");
  		return -EAGAIN;
  	}
dfd56b8b3   Eric Dumazet   net: use IS_ENABL...
150
  #if IS_ENABLED(CONFIG_IPV6)
c0d56408e   Kazunori MIYAZAWA   [IPSEC]: Changing...
151
152
153
154
155
156
157
  	if (inet_add_protocol(&tunnel64_protocol, IPPROTO_IPV6)) {
  		printk(KERN_ERR "tunnel64 init: can't add protocol
  ");
  		inet_del_protocol(&tunnel4_protocol, IPPROTO_IPIP);
  		return -EAGAIN;
  	}
  #endif
d2acc3479   Herbert Xu   [INET]: Introduce...
158
159
160
161
162
  	return 0;
  }
  
  static void __exit tunnel4_fini(void)
  {
dfd56b8b3   Eric Dumazet   net: use IS_ENABL...
163
  #if IS_ENABLED(CONFIG_IPV6)
c0d56408e   Kazunori MIYAZAWA   [IPSEC]: Changing...
164
165
166
167
  	if (inet_del_protocol(&tunnel64_protocol, IPPROTO_IPV6))
  		printk(KERN_ERR "tunnel64 close: can't remove protocol
  ");
  #endif
d2acc3479   Herbert Xu   [INET]: Introduce...
168
169
170
171
172
173
174
175
  	if (inet_del_protocol(&tunnel4_protocol, IPPROTO_IPIP))
  		printk(KERN_ERR "tunnel4 close: can't remove protocol
  ");
  }
  
  module_init(tunnel4_init);
  module_exit(tunnel4_fini);
  MODULE_LICENSE("GPL");