Blame view

net/ipv6/ip6_tunnel.c 58.2 KB
2874c5fd2   Thomas Gleixner   treewide: Replace...
1
  // SPDX-License-Identifier: GPL-2.0-or-later
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2
  /*
c4d3efafc   Yasuyuki Kozakai   [IPV6] IP6TUNNEL:...
3
   *	IPv6 tunneling device
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
4
5
6
   *	Linux INET6 implementation
   *
   *	Authors:
1ab1457c4   YOSHIFUJI Hideaki   [NET] IPV6: Fix w...
7
   *	Ville Nuorvala		<vnuorval@tcs.hut.fi>
c4d3efafc   Yasuyuki Kozakai   [IPV6] IP6TUNNEL:...
8
   *	Yasuyuki Kozakai	<kozakai@linux-ipv6.org>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
9
   *
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
10
   *      Based on:
c4d3efafc   Yasuyuki Kozakai   [IPV6] IP6TUNNEL:...
11
   *      linux/net/ipv6/sit.c and linux/net/ipv4/ipip.c
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
12
13
   *
   *      RFC 2473
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
14
   */
f32138319   Joe Perches   net: ipv6: Standa...
15
  #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
16
  #include <linux/module.h>
4fc268d24   Randy Dunlap   [PATCH] capable/c...
17
  #include <linux/capability.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
18
19
20
  #include <linux/errno.h>
  #include <linux/types.h>
  #include <linux/sockios.h>
c4d3efafc   Yasuyuki Kozakai   [IPV6] IP6TUNNEL:...
21
  #include <linux/icmp.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
22
23
24
  #include <linux/if.h>
  #include <linux/in.h>
  #include <linux/ip.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
25
26
27
28
29
30
31
32
33
  #include <linux/net.h>
  #include <linux/in6.h>
  #include <linux/netdevice.h>
  #include <linux/if_arp.h>
  #include <linux/icmpv6.h>
  #include <linux/init.h>
  #include <linux/route.h>
  #include <linux/rtnetlink.h>
  #include <linux/netfilter_ipv6.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
34
  #include <linux/slab.h>
ddbe50320   Eric Dumazet   ipv6: add ipv6_ad...
35
  #include <linux/hash.h>
e837735ec   Nicolas Dichtel   ip6_tunnel: ensur...
36
  #include <linux/etherdevice.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
37

7c0f6ba68   Linus Torvalds   Replace <asm/uacc...
38
  #include <linux/uaccess.h>
60063497a   Arun Sharma   atomic: use <linu...
39
  #include <linux/atomic.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
40

c4d3efafc   Yasuyuki Kozakai   [IPV6] IP6TUNNEL:...
41
  #include <net/icmp.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
42
  #include <net/ip.h>
c54419321   Pravin B Shelar   GRE: Refactor GRE...
43
  #include <net/ip_tunnels.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
44
  #include <net/ipv6.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
45
46
47
48
49
50
  #include <net/ip6_route.h>
  #include <net/addrconf.h>
  #include <net/ip6_tunnel.h>
  #include <net/xfrm.h>
  #include <net/dsfield.h>
  #include <net/inet_ecn.h>
13eeb8e92   Pavel Emelyanov   [IP6TUNNEL]: Intr...
51
52
  #include <net/net_namespace.h>
  #include <net/netns/generic.h>
8d79266bc   Alexei Starovoitov   ip6_tunnel: add c...
53
  #include <net/dst_metadata.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
54
55
  
  MODULE_AUTHOR("Ville Nuorvala");
c4d3efafc   Yasuyuki Kozakai   [IPV6] IP6TUNNEL:...
56
  MODULE_DESCRIPTION("IPv6 tunneling device");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
57
  MODULE_LICENSE("GPL");
f98f89a01   Tom Gundersen   net: tunnels - en...
58
  MODULE_ALIAS_RTNL_LINK("ip6tnl");
6dfbd87a2   stephen hemminger   ip6ip6: autoload ...
59
  MODULE_ALIAS_NETDEV("ip6tnl0");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
60

e87a8f24c   Jiri Kosina   net: resolve symb...
61
62
  #define IP6_TUNNEL_HASH_SIZE_SHIFT  5
  #define IP6_TUNNEL_HASH_SIZE (1 << IP6_TUNNEL_HASH_SIZE_SHIFT)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
63

f4e0b4c5e   Nicolas Dichtel   ip6tnl/sit: drop ...
64
65
66
  static bool log_ecn_error = true;
  module_param(log_ecn_error, bool, 0644);
  MODULE_PARM_DESC(log_ecn_error, "Log packets received with corrupted ECN");
ddbe50320   Eric Dumazet   ipv6: add ipv6_ad...
67
68
69
  static u32 HASH(const struct in6_addr *addr1, const struct in6_addr *addr2)
  {
  	u32 hash = ipv6_addr_hash(addr1) ^ ipv6_addr_hash(addr2);
e87a8f24c   Jiri Kosina   net: resolve symb...
70
  	return hash_32(hash, IP6_TUNNEL_HASH_SIZE_SHIFT);
ddbe50320   Eric Dumazet   ipv6: add ipv6_ad...
71
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
72

8560f2266   Eric Dumazet   ip6tnl: percpu st...
73
  static int ip6_tnl_dev_init(struct net_device *dev);
3144581cb   Yasuyuki Kozakai   [IPV6] IP6TUNNEL:...
74
  static void ip6_tnl_dev_setup(struct net_device *dev);
c075b1309   Nicolas Dichtel   ip6tnl: advertise...
75
  static struct rtnl_link_ops ip6_link_ops __read_mostly;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
76

c7d03a00b   Alexey Dobriyan   netns: make struc...
77
  static unsigned int ip6_tnl_net_id __read_mostly;
13eeb8e92   Pavel Emelyanov   [IP6TUNNEL]: Intr...
78
  struct ip6_tnl_net {
15820e129   Pavel Emelyanov   [IP6TUNNEL]: Make...
79
80
  	/* the IPv6 tunnel fallback device */
  	struct net_device *fb_tnl_dev;
3e6c9fb5f   Pavel Emelyanov   [IP6TUNNEL]: Make...
81
  	/* lists for storing tunnels in use */
e87a8f24c   Jiri Kosina   net: resolve symb...
82
  	struct ip6_tnl __rcu *tnls_r_l[IP6_TUNNEL_HASH_SIZE];
947676326   Eric Dumazet   ip6tnl: get rid o...
83
84
  	struct ip6_tnl __rcu *tnls_wc[1];
  	struct ip6_tnl __rcu **tnls[2];
8d79266bc   Alexei Starovoitov   ip6_tunnel: add c...
85
  	struct ip6_tnl __rcu *collect_md_tun;
13eeb8e92   Pavel Emelyanov   [IP6TUNNEL]: Intr...
86
  };
f200e98d9   Vadim Fedorenko   ip6_tunnel: add g...
87
88
89
90
  static inline int ip6_tnl_mpls_supported(void)
  {
  	return IS_ENABLED(CONFIG_MPLS);
  }
8560f2266   Eric Dumazet   ip6tnl: percpu st...
91
92
  static struct net_device_stats *ip6_get_stats(struct net_device *dev)
  {
56a4342df   David S. Miller   Merge branch 'mas...
93
  	struct pcpu_sw_netstats tmp, sum = { 0 };
8560f2266   Eric Dumazet   ip6tnl: percpu st...
94
95
96
  	int i;
  
  	for_each_possible_cpu(i) {
abb6013cc   Li RongQing   ipv6: fix the use...
97
  		unsigned int start;
8f84985fe   Li RongQing   net: unify the pc...
98
99
  		const struct pcpu_sw_netstats *tstats =
  						   per_cpu_ptr(dev->tstats, i);
8560f2266   Eric Dumazet   ip6tnl: percpu st...
100

abb6013cc   Li RongQing   ipv6: fix the use...
101
  		do {
57a7744e0   Eric W. Biederman   net: Replace u64_...
102
  			start = u64_stats_fetch_begin_irq(&tstats->syncp);
abb6013cc   Li RongQing   ipv6: fix the use...
103
104
105
106
  			tmp.rx_packets = tstats->rx_packets;
  			tmp.rx_bytes = tstats->rx_bytes;
  			tmp.tx_packets = tstats->tx_packets;
  			tmp.tx_bytes =  tstats->tx_bytes;
57a7744e0   Eric W. Biederman   net: Replace u64_...
107
  		} while (u64_stats_fetch_retry_irq(&tstats->syncp, start));
abb6013cc   Li RongQing   ipv6: fix the use...
108
109
110
111
112
  
  		sum.rx_packets += tmp.rx_packets;
  		sum.rx_bytes   += tmp.rx_bytes;
  		sum.tx_packets += tmp.tx_packets;
  		sum.tx_bytes   += tmp.tx_bytes;
8560f2266   Eric Dumazet   ip6tnl: percpu st...
113
114
115
116
117
118
119
  	}
  	dev->stats.rx_packets = sum.rx_packets;
  	dev->stats.rx_bytes   = sum.rx_bytes;
  	dev->stats.tx_packets = sum.tx_packets;
  	dev->stats.tx_bytes   = sum.tx_bytes;
  	return &dev->stats;
  }
b51cd7c83   Andrew Lunn   net: ipv6: kernel...
120
121
  #define for_each_ip6_tunnel_rcu(start) \
  	for (t = rcu_dereference(start); t; t = rcu_dereference(t->next))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
122
  /**
3144581cb   Yasuyuki Kozakai   [IPV6] IP6TUNNEL:...
123
   * ip6_tnl_lookup - fetch tunnel matching the end-point addresses
b51cd7c83   Andrew Lunn   net: ipv6: kernel...
124
   *   @net: network namespace
5fdcce211   William Dauchy   net, ip6_tunnel: ...
125
   *   @link: ifindex of underlying interface
1ab1457c4   YOSHIFUJI Hideaki   [NET] IPV6: Fix w...
126
127
   *   @remote: the address of the tunnel exit-point
   *   @local: the address of the tunnel entry-point
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
128
   *
1ab1457c4   YOSHIFUJI Hideaki   [NET] IPV6: Fix w...
129
   * Return:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
130
   *   tunnel matching given end-points if found,
1ab1457c4   YOSHIFUJI Hideaki   [NET] IPV6: Fix w...
131
   *   else fallback tunnel if its device is up,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
132
133
134
135
   *   else %NULL
   **/
  
  static struct ip6_tnl *
5fdcce211   William Dauchy   net, ip6_tunnel: ...
136
137
  ip6_tnl_lookup(struct net *net, int link,
  	       const struct in6_addr *remote, const struct in6_addr *local)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
138
  {
ddbe50320   Eric Dumazet   ipv6: add ipv6_ad...
139
  	unsigned int hash = HASH(remote, local);
5fdcce211   William Dauchy   net, ip6_tunnel: ...
140
  	struct ip6_tnl *t, *cand = NULL;
3e6c9fb5f   Pavel Emelyanov   [IP6TUNNEL]: Make...
141
  	struct ip6_tnl_net *ip6n = net_generic(net, ip6_tnl_net_id);
ea3dc9601   Steffen Klassert   ip6_tunnel: Add s...
142
  	struct in6_addr any;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
143

ddbe50320   Eric Dumazet   ipv6: add ipv6_ad...
144
  	for_each_ip6_tunnel_rcu(ip6n->tnls_r_l[hash]) {
5fdcce211   William Dauchy   net, ip6_tunnel: ...
145
146
147
148
149
150
  		if (!ipv6_addr_equal(local, &t->parms.laddr) ||
  		    !ipv6_addr_equal(remote, &t->parms.raddr) ||
  		    !(t->dev->flags & IFF_UP))
  			continue;
  
  		if (link == t->parms.link)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
151
  			return t;
5fdcce211   William Dauchy   net, ip6_tunnel: ...
152
153
  		else
  			cand = t;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
154
  	}
ea3dc9601   Steffen Klassert   ip6_tunnel: Add s...
155
156
157
158
  
  	memset(&any, 0, sizeof(any));
  	hash = HASH(&any, local);
  	for_each_ip6_tunnel_rcu(ip6n->tnls_r_l[hash]) {
5fdcce211   William Dauchy   net, ip6_tunnel: ...
159
160
161
162
163
164
  		if (!ipv6_addr_equal(local, &t->parms.laddr) ||
  		    !ipv6_addr_any(&t->parms.raddr) ||
  		    !(t->dev->flags & IFF_UP))
  			continue;
  
  		if (link == t->parms.link)
ea3dc9601   Steffen Klassert   ip6_tunnel: Add s...
165
  			return t;
5fdcce211   William Dauchy   net, ip6_tunnel: ...
166
167
  		else if (!cand)
  			cand = t;
ea3dc9601   Steffen Klassert   ip6_tunnel: Add s...
168
169
170
171
  	}
  
  	hash = HASH(remote, &any);
  	for_each_ip6_tunnel_rcu(ip6n->tnls_r_l[hash]) {
5fdcce211   William Dauchy   net, ip6_tunnel: ...
172
173
174
175
176
177
  		if (!ipv6_addr_equal(remote, &t->parms.raddr) ||
  		    !ipv6_addr_any(&t->parms.laddr) ||
  		    !(t->dev->flags & IFF_UP))
  			continue;
  
  		if (link == t->parms.link)
ea3dc9601   Steffen Klassert   ip6_tunnel: Add s...
178
  			return t;
5fdcce211   William Dauchy   net, ip6_tunnel: ...
179
180
  		else if (!cand)
  			cand = t;
ea3dc9601   Steffen Klassert   ip6_tunnel: Add s...
181
  	}
5fdcce211   William Dauchy   net, ip6_tunnel: ...
182
183
  	if (cand)
  		return cand;
8d79266bc   Alexei Starovoitov   ip6_tunnel: add c...
184
  	t = rcu_dereference(ip6n->collect_md_tun);
6c1cb4393   Haishuang Yan   ip6_tunnel: fix i...
185
  	if (t && t->dev->flags & IFF_UP)
8d79266bc   Alexei Starovoitov   ip6_tunnel: add c...
186
  		return t;
2922bc8ae   Eric Dumazet   ip6tnl: convert h...
187
188
  	t = rcu_dereference(ip6n->tnls_wc[0]);
  	if (t && (t->dev->flags & IFF_UP))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
189
190
191
192
193
194
  		return t;
  
  	return NULL;
  }
  
  /**
3144581cb   Yasuyuki Kozakai   [IPV6] IP6TUNNEL:...
195
   * ip6_tnl_bucket - get head of list matching given tunnel parameters
1ab1457c4   YOSHIFUJI Hideaki   [NET] IPV6: Fix w...
196
   *   @p: parameters containing tunnel end-points
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
197
198
   *
   * Description:
3144581cb   Yasuyuki Kozakai   [IPV6] IP6TUNNEL:...
199
   *   ip6_tnl_bucket() returns the head of the list matching the
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
200
201
   *   &struct in6_addr entries laddr and raddr in @p.
   *
1ab1457c4   YOSHIFUJI Hideaki   [NET] IPV6: Fix w...
202
   * Return: head of IPv6 tunnel list
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
203
   **/
947676326   Eric Dumazet   ip6tnl: get rid o...
204
  static struct ip6_tnl __rcu **
c12b395a4   xeb@mail.ru   gre: Support GRE ...
205
  ip6_tnl_bucket(struct ip6_tnl_net *ip6n, const struct __ip6_tnl_parm *p)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
206
  {
b71d1d426   Eric Dumazet   inet: constify ip...
207
208
  	const struct in6_addr *remote = &p->raddr;
  	const struct in6_addr *local = &p->laddr;
95c961747   Eric Dumazet   net: cleanup unsi...
209
  	unsigned int h = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
210
211
212
213
  	int prio = 0;
  
  	if (!ipv6_addr_any(remote) || !ipv6_addr_any(local)) {
  		prio = 1;
ddbe50320   Eric Dumazet   ipv6: add ipv6_ad...
214
  		h = HASH(remote, local);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
215
  	}
3e6c9fb5f   Pavel Emelyanov   [IP6TUNNEL]: Make...
216
  	return &ip6n->tnls[prio][h];
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
217
218
219
  }
  
  /**
3144581cb   Yasuyuki Kozakai   [IPV6] IP6TUNNEL:...
220
   * ip6_tnl_link - add tunnel to hash table
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
221
222
223
224
   *   @t: tunnel to be added
   **/
  
  static void
2dd02c897   Pavel Emelyanov   [IP6TUNNEL]: Add ...
225
  ip6_tnl_link(struct ip6_tnl_net *ip6n, struct ip6_tnl *t)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
226
  {
947676326   Eric Dumazet   ip6tnl: get rid o...
227
  	struct ip6_tnl __rcu **tp = ip6_tnl_bucket(ip6n, &t->parms);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
228

8d79266bc   Alexei Starovoitov   ip6_tunnel: add c...
229
230
  	if (t->parms.collect_md)
  		rcu_assign_pointer(ip6n->collect_md_tun, t);
cf778b00e   Eric Dumazet   net: reintroduce ...
231
232
  	rcu_assign_pointer(t->next , rtnl_dereference(*tp));
  	rcu_assign_pointer(*tp, t);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
233
234
235
  }
  
  /**
3144581cb   Yasuyuki Kozakai   [IPV6] IP6TUNNEL:...
236
   * ip6_tnl_unlink - remove tunnel from hash table
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
237
238
239
240
   *   @t: tunnel to be removed
   **/
  
  static void
2dd02c897   Pavel Emelyanov   [IP6TUNNEL]: Add ...
241
  ip6_tnl_unlink(struct ip6_tnl_net *ip6n, struct ip6_tnl *t)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
242
  {
947676326   Eric Dumazet   ip6tnl: get rid o...
243
244
  	struct ip6_tnl __rcu **tp;
  	struct ip6_tnl *iter;
8d79266bc   Alexei Starovoitov   ip6_tunnel: add c...
245
246
  	if (t->parms.collect_md)
  		rcu_assign_pointer(ip6n->collect_md_tun, NULL);
947676326   Eric Dumazet   ip6tnl: get rid o...
247
248
249
250
  	for (tp = ip6_tnl_bucket(ip6n, &t->parms);
  	     (iter = rtnl_dereference(*tp)) != NULL;
  	     tp = &iter->next) {
  		if (t == iter) {
cf778b00e   Eric Dumazet   net: reintroduce ...
251
  			rcu_assign_pointer(*tp, t->next);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
252
253
254
255
  			break;
  		}
  	}
  }
8560f2266   Eric Dumazet   ip6tnl: percpu st...
256
257
  static void ip6_dev_free(struct net_device *dev)
  {
cdf3464e6   Martin KaFai Lau   ipv6: Fix dst_ent...
258
  	struct ip6_tnl *t = netdev_priv(dev);
0d3c703a9   Tom Herbert   ipv6: Cleanup IPv...
259
  	gro_cells_destroy(&t->gro_cells);
607f725f6   Paolo Abeni   net: replace dst_...
260
  	dst_cache_destroy(&t->dst_cache);
8560f2266   Eric Dumazet   ip6tnl: percpu st...
261
  	free_percpu(dev->tstats);
8560f2266   Eric Dumazet   ip6tnl: percpu st...
262
  }
0b1124572   Nicolas Dichtel   ip6tnl: add suppo...
263
264
265
266
267
268
269
270
  static int ip6_tnl_create2(struct net_device *dev)
  {
  	struct ip6_tnl *t = netdev_priv(dev);
  	struct net *net = dev_net(dev);
  	struct ip6_tnl_net *ip6n = net_generic(net, ip6_tnl_net_id);
  	int err;
  
  	t = netdev_priv(dev);
0b1124572   Nicolas Dichtel   ip6tnl: add suppo...
271

b6ee376cb   Thadeu Lima de Souza Cascardo   ip6_tunnel: set r...
272
  	dev->rtnl_link_ops = &ip6_link_ops;
0b1124572   Nicolas Dichtel   ip6tnl: add suppo...
273
274
275
276
277
  	err = register_netdevice(dev);
  	if (err < 0)
  		goto out;
  
  	strcpy(t->parms.name, dev->name);
0b1124572   Nicolas Dichtel   ip6tnl: add suppo...
278
279
280
281
282
283
284
285
  
  	dev_hold(dev);
  	ip6_tnl_link(ip6n, t);
  	return 0;
  
  out:
  	return err;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
286
  /**
2c53040f0   Ben Hutchings   net: Fix (nearly-...
287
   * ip6_tnl_create - create a new tunnel
b51cd7c83   Andrew Lunn   net: ipv6: kernel...
288
   *   @net: network namespace
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
289
   *   @p: tunnel parameters
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
290
291
292
   *
   * Description:
   *   Create tunnel matching given parameters.
1ab1457c4   YOSHIFUJI Hideaki   [NET] IPV6: Fix w...
293
294
   *
   * Return:
37355565b   Nicolas Dichtel   ip6_tunnel: fix e...
295
   *   created tunnel or error pointer
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
296
   **/
c12b395a4   xeb@mail.ru   gre: Support GRE ...
297
  static struct ip6_tnl *ip6_tnl_create(struct net *net, struct __ip6_tnl_parm *p)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
298
299
300
301
  {
  	struct net_device *dev;
  	struct ip6_tnl *t;
  	char name[IFNAMSIZ];
db7a65e3a   Eric Dumazet   ip6_tunnel: bette...
302
  	int err = -E2BIG;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
303

db7a65e3a   Eric Dumazet   ip6_tunnel: bette...
304
305
306
  	if (p->name[0]) {
  		if (!dev_valid_name(p->name))
  			goto failed;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
307
  		strlcpy(name, p->name, IFNAMSIZ);
db7a65e3a   Eric Dumazet   ip6_tunnel: bette...
308
  	} else {
34cc7ba63   Pavel Emelyanov   [IP_TUNNEL]: Don'...
309
  		sprintf(name, "ip6tnl%%d");
db7a65e3a   Eric Dumazet   ip6_tunnel: bette...
310
311
  	}
  	err = -ENOMEM;
c835a6773   Tom Gundersen   net: set name_ass...
312
313
  	dev = alloc_netdev(sizeof(*t), name, NET_NAME_UNKNOWN,
  			   ip6_tnl_dev_setup);
63159f29b   Ian Morris   ipv6: coding styl...
314
  	if (!dev)
567131a72   Ville Nuorvala   [IPV6]: Fix SIOCC...
315
  		goto failed;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
316

554eb2778   Pavel Emelyanov   [IP6TUNNEL]: Allo...
317
  	dev_net_set(dev, net);
2941a4863   Patrick McHardy   [NET]: Convert ne...
318
  	t = netdev_priv(dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
319
  	t->parms = *p;
0bd876282   Nicolas Dichtel   ip6tnl: add x-net...
320
  	t->net = dev_net(dev);
0b1124572   Nicolas Dichtel   ip6tnl: add suppo...
321
  	err = ip6_tnl_create2(dev);
8560f2266   Eric Dumazet   ip6tnl: percpu st...
322
323
  	if (err < 0)
  		goto failed_free;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
324

567131a72   Ville Nuorvala   [IPV6]: Fix SIOCC...
325
  	return t;
b37d428b2   Pavel Emelyanov   [INET]: Don't cre...
326
327
  
  failed_free:
cf124db56   David S. Miller   net: Fix inconsis...
328
  	free_netdev(dev);
567131a72   Ville Nuorvala   [IPV6]: Fix SIOCC...
329
  failed:
37355565b   Nicolas Dichtel   ip6_tunnel: fix e...
330
  	return ERR_PTR(err);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
331
332
333
  }
  
  /**
3144581cb   Yasuyuki Kozakai   [IPV6] IP6TUNNEL:...
334
   * ip6_tnl_locate - find or create tunnel matching given parameters
b51cd7c83   Andrew Lunn   net: ipv6: kernel...
335
   *   @net: network namespace
1ab1457c4   YOSHIFUJI Hideaki   [NET] IPV6: Fix w...
336
   *   @p: tunnel parameters
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
337
338
339
   *   @create: != 0 if allowed to create new tunnel if no match found
   *
   * Description:
3144581cb   Yasuyuki Kozakai   [IPV6] IP6TUNNEL:...
340
   *   ip6_tnl_locate() first tries to locate an existing tunnel
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
341
342
343
344
   *   based on @parms. If this is unsuccessful, but @create is set a new
   *   tunnel device is created and registered for use.
   *
   * Return:
37355565b   Nicolas Dichtel   ip6_tunnel: fix e...
345
   *   matching tunnel or error pointer
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
346
   **/
2dd02c897   Pavel Emelyanov   [IP6TUNNEL]: Add ...
347
  static struct ip6_tnl *ip6_tnl_locate(struct net *net,
c12b395a4   xeb@mail.ru   gre: Support GRE ...
348
  		struct __ip6_tnl_parm *p, int create)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
349
  {
b71d1d426   Eric Dumazet   inet: constify ip...
350
351
  	const struct in6_addr *remote = &p->raddr;
  	const struct in6_addr *local = &p->laddr;
947676326   Eric Dumazet   ip6tnl: get rid o...
352
  	struct ip6_tnl __rcu **tp;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
353
  	struct ip6_tnl *t;
2dd02c897   Pavel Emelyanov   [IP6TUNNEL]: Add ...
354
  	struct ip6_tnl_net *ip6n = net_generic(net, ip6_tnl_net_id);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
355

947676326   Eric Dumazet   ip6tnl: get rid o...
356
357
358
  	for (tp = ip6_tnl_bucket(ip6n, p);
  	     (t = rtnl_dereference(*tp)) != NULL;
  	     tp = &t->next) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
359
  		if (ipv6_addr_equal(local, &t->parms.laddr) &&
5fdcce211   William Dauchy   net, ip6_tunnel: ...
360
361
  		    ipv6_addr_equal(remote, &t->parms.raddr) &&
  		    p->link == t->parms.link) {
2b0bb01b6   Steffen Klassert   ip6_tunnel: Retur...
362
  			if (create)
37355565b   Nicolas Dichtel   ip6_tunnel: fix e...
363
  				return ERR_PTR(-EEXIST);
2b0bb01b6   Steffen Klassert   ip6_tunnel: Retur...
364

567131a72   Ville Nuorvala   [IPV6]: Fix SIOCC...
365
  			return t;
2b0bb01b6   Steffen Klassert   ip6_tunnel: Retur...
366
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
367
368
  	}
  	if (!create)
37355565b   Nicolas Dichtel   ip6_tunnel: fix e...
369
  		return ERR_PTR(-ENODEV);
2dd02c897   Pavel Emelyanov   [IP6TUNNEL]: Add ...
370
  	return ip6_tnl_create(net, p);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
371
372
373
  }
  
  /**
3144581cb   Yasuyuki Kozakai   [IPV6] IP6TUNNEL:...
374
   * ip6_tnl_dev_uninit - tunnel device uninitializer
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
375
   *   @dev: the device to be destroyed
1ab1457c4   YOSHIFUJI Hideaki   [NET] IPV6: Fix w...
376
   *
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
377
   * Description:
3144581cb   Yasuyuki Kozakai   [IPV6] IP6TUNNEL:...
378
   *   ip6_tnl_dev_uninit() removes tunnel from its list
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
379
380
381
   **/
  
  static void
3144581cb   Yasuyuki Kozakai   [IPV6] IP6TUNNEL:...
382
  ip6_tnl_dev_uninit(struct net_device *dev)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
383
  {
2941a4863   Patrick McHardy   [NET]: Convert ne...
384
  	struct ip6_tnl *t = netdev_priv(dev);
0bd876282   Nicolas Dichtel   ip6tnl: add x-net...
385
  	struct net *net = t->net;
2dd02c897   Pavel Emelyanov   [IP6TUNNEL]: Add ...
386
  	struct ip6_tnl_net *ip6n = net_generic(net, ip6_tnl_net_id);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
387

947676326   Eric Dumazet   ip6tnl: get rid o...
388
  	if (dev == ip6n->fb_tnl_dev)
a9b3cd7f3   Stephen Hemminger   rcu: convert uses...
389
  		RCU_INIT_POINTER(ip6n->tnls_wc[0], NULL);
947676326   Eric Dumazet   ip6tnl: get rid o...
390
  	else
2dd02c897   Pavel Emelyanov   [IP6TUNNEL]: Add ...
391
  		ip6_tnl_unlink(ip6n, t);
607f725f6   Paolo Abeni   net: replace dst_...
392
  	dst_cache_reset(&t->dst_cache);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
393
394
395
396
397
398
399
  	dev_put(dev);
  }
  
  /**
   * parse_tvl_tnl_enc_lim - handle encapsulation limit option
   *   @skb: received socket buffer
   *
1ab1457c4   YOSHIFUJI Hideaki   [NET] IPV6: Fix w...
400
401
   * Return:
   *   0 if none was found,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
402
403
   *   else index to encapsulation limit
   **/
c12b395a4   xeb@mail.ru   gre: Support GRE ...
404
  __u16 ip6_tnl_parse_tlv_enc_lim(struct sk_buff *skb, __u8 *raw)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
405
  {
fbfa743a9   Eric Dumazet   ipv6: fix ip6_tnl...
406
407
408
409
  	const struct ipv6hdr *ipv6h = (const struct ipv6hdr *)raw;
  	unsigned int nhoff = raw - skb->data;
  	unsigned int off = nhoff + sizeof(*ipv6h);
  	u8 next, nexthdr = ipv6h->nexthdr;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
410
411
  
  	while (ipv6_ext_hdr(nexthdr) && nexthdr != NEXTHDR_NONE) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
412
  		struct ipv6_opt_hdr *hdr;
fbfa743a9   Eric Dumazet   ipv6: fix ip6_tnl...
413
414
415
  		u16 optlen;
  
  		if (!pskb_may_pull(skb, off + sizeof(*hdr)))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
416
  			break;
fbfa743a9   Eric Dumazet   ipv6: fix ip6_tnl...
417
  		hdr = (struct ipv6_opt_hdr *)(skb->data + off);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
418
419
420
421
422
423
  		if (nexthdr == NEXTHDR_FRAGMENT) {
  			struct frag_hdr *frag_hdr = (struct frag_hdr *) hdr;
  			if (frag_hdr->frag_off)
  				break;
  			optlen = 8;
  		} else if (nexthdr == NEXTHDR_AUTH) {
416e8126a   yangxingwu   ipv6: Use ipv6_au...
424
  			optlen = ipv6_authlen(hdr);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
425
426
427
  		} else {
  			optlen = ipv6_optlen(hdr);
  		}
fbfa743a9   Eric Dumazet   ipv6: fix ip6_tnl...
428
429
430
431
  		/* cache hdr->nexthdr, since pskb_may_pull() might
  		 * invalidate hdr
  		 */
  		next = hdr->nexthdr;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
432
  		if (nexthdr == NEXTHDR_DEST) {
fbfa743a9   Eric Dumazet   ipv6: fix ip6_tnl...
433
434
435
436
437
  			u16 i = 2;
  
  			/* Remember : hdr is no longer valid at this point. */
  			if (!pskb_may_pull(skb, off + optlen))
  				break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
438
439
440
441
  			while (1) {
  				struct ipv6_tlv_tnl_enc_lim *tel;
  
  				/* No more room for encapsulation limit */
fbfa743a9   Eric Dumazet   ipv6: fix ip6_tnl...
442
  				if (i + sizeof(*tel) > optlen)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
443
  					break;
63117f09c   Dan Carpenter   ipv6: pointer mat...
444
  				tel = (struct ipv6_tlv_tnl_enc_lim *)(skb->data + off + i);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
445
446
447
  				/* return index of option if found and valid */
  				if (tel->type == IPV6_TLV_TNL_ENCAP_LIMIT &&
  				    tel->length == 1)
fbfa743a9   Eric Dumazet   ipv6: fix ip6_tnl...
448
  					return i + off - nhoff;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
449
450
451
452
453
454
455
  				/* else jump to next option */
  				if (tel->type)
  					i += tel->length + 2;
  				else
  					i++;
  			}
  		}
fbfa743a9   Eric Dumazet   ipv6: fix ip6_tnl...
456
  		nexthdr = next;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
457
458
459
460
  		off += optlen;
  	}
  	return 0;
  }
c12b395a4   xeb@mail.ru   gre: Support GRE ...
461
  EXPORT_SYMBOL(ip6_tnl_parse_tlv_enc_lim);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
462
463
  
  /**
e490d1d85   Yasuyuki Kozakai   [IPV6] IP6TUNNEL:...
464
   * ip6_tnl_err - tunnel error handler
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
465
466
   *
   * Description:
e490d1d85   Yasuyuki Kozakai   [IPV6] IP6TUNNEL:...
467
   *   ip6_tnl_err() should handle errors in the tunnel according
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
468
469
   *   to the specifications in RFC 2473.
   **/
d2acc3479   Herbert Xu   [INET]: Introduce...
470
  static int
502b09356   Yasuyuki Kozakai   [IPV6] IP6TUNNEL:...
471
  ip6_tnl_err(struct sk_buff *skb, __u8 ipproto, struct inet6_skb_parm *opt,
d5fdd6bab   Brian Haley   ipv6: Use correct...
472
  	    u8 *type, u8 *code, int *msg, __u32 *info, int offset)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
473
  {
383c1f887   Xin Long   ip6_tunnel: add t...
474
475
  	const struct ipv6hdr *ipv6h = (const struct ipv6hdr *)skb->data;
  	struct net *net = dev_net(skb->dev);
d5fdd6bab   Brian Haley   ipv6: Use correct...
476
477
  	u8 rel_type = ICMPV6_DEST_UNREACH;
  	u8 rel_code = ICMPV6_ADDR_UNREACH;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
478
  	__u32 rel_info = 0;
383c1f887   Xin Long   ip6_tunnel: add t...
479
  	struct ip6_tnl *t;
d2acc3479   Herbert Xu   [INET]: Introduce...
480
  	int err = -ENOENT;
383c1f887   Xin Long   ip6_tunnel: add t...
481
482
483
  	int rel_msg = 0;
  	u8 tproto;
  	__u16 len;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
484

1ab1457c4   YOSHIFUJI Hideaki   [NET] IPV6: Fix w...
485
486
  	/* If the packet doesn't contain the original IPv6 header we are
  	   in trouble since we might need the source address for further
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
487
  	   processing of the error. */
2922bc8ae   Eric Dumazet   ip6tnl: convert h...
488
  	rcu_read_lock();
5fdcce211   William Dauchy   net, ip6_tunnel: ...
489
  	t = ip6_tnl_lookup(dev_net(skb->dev), skb->dev->ifindex, &ipv6h->daddr, &ipv6h->saddr);
63159f29b   Ian Morris   ipv6: coding styl...
490
  	if (!t)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
491
  		goto out;
6aa7de059   Mark Rutland   locking/atomics: ...
492
  	tproto = READ_ONCE(t->parms.proto);
acf722f73   Alexey Andriyanov   ip6_tunnel: allow...
493
  	if (tproto != ipproto && tproto != 0)
502b09356   Yasuyuki Kozakai   [IPV6] IP6TUNNEL:...
494
  		goto out;
d2acc3479   Herbert Xu   [INET]: Introduce...
495
  	err = 0;
e490d1d85   Yasuyuki Kozakai   [IPV6] IP6TUNNEL:...
496
  	switch (*type) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
497
  	case ICMPV6_DEST_UNREACH:
17a10c921   Matt Bennett   ip6_tunnel: Reduc...
498
499
500
  		net_dbg_ratelimited("%s: Path to destination invalid or inactive!
  ",
  				    t->parms.name);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
501
502
503
  		rel_msg = 1;
  		break;
  	case ICMPV6_TIME_EXCEED:
e490d1d85   Yasuyuki Kozakai   [IPV6] IP6TUNNEL:...
504
  		if ((*code) == ICMPV6_EXC_HOPLIMIT) {
17a10c921   Matt Bennett   ip6_tunnel: Reduc...
505
506
507
  			net_dbg_ratelimited("%s: Too small hop limit or routing loop in tunnel!
  ",
  					    t->parms.name);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
508
509
510
  			rel_msg = 1;
  		}
  		break;
46d30cb10   Kees Cook   net: ip6_gre: Dis...
511
512
513
  	case ICMPV6_PARAMPROB: {
  		struct ipv6_tlv_tnl_enc_lim *tel;
  		__u32 teli;
107a5fe61   Ville Nuorvala   [IPV6]: Improve I...
514
  		teli = 0;
e490d1d85   Yasuyuki Kozakai   [IPV6] IP6TUNNEL:...
515
  		if ((*code) == ICMPV6_HDR_FIELD)
c12b395a4   xeb@mail.ru   gre: Support GRE ...
516
  			teli = ip6_tnl_parse_tlv_enc_lim(skb, skb->data);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
517

704eae1f3   Al Viro   ip6_tunnel - endi...
518
  		if (teli && teli == *info - 2) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
519
520
  			tel = (struct ipv6_tlv_tnl_enc_lim *) &skb->data[teli];
  			if (tel->encap_limit == 0) {
17a10c921   Matt Bennett   ip6_tunnel: Reduc...
521
522
523
  				net_dbg_ratelimited("%s: Too small encapsulation limit or routing loop in tunnel!
  ",
  						    t->parms.name);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
524
525
  				rel_msg = 1;
  			}
e87cc4728   Joe Perches   net: Convert net_...
526
  		} else {
17a10c921   Matt Bennett   ip6_tunnel: Reduc...
527
528
529
  			net_dbg_ratelimited("%s: Recipient unable to parse tunneled packet!
  ",
  					    t->parms.name);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
530
531
  		}
  		break;
46d30cb10   Kees Cook   net: ip6_gre: Dis...
532
533
534
  	}
  	case ICMPV6_PKT_TOOBIG: {
  		__u32 mtu;
b00f54324   Xin Long   ip6_tunnel: proce...
535
536
  		ip6_update_pmtu(skb, net, htonl(*info), 0, 0,
  				sock_net_uid(net, NULL));
704eae1f3   Al Viro   ip6_tunnel - endi...
537
  		mtu = *info - offset;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
538
539
  		if (mtu < IPV6_MIN_MTU)
  			mtu = IPV6_MIN_MTU;
e5d08d718   Ian Morris   ipv6: coding styl...
540
541
  		len = sizeof(*ipv6h) + ntohs(ipv6h->payload_len);
  		if (len > mtu) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
542
543
544
545
546
547
  			rel_type = ICMPV6_PKT_TOOBIG;
  			rel_code = 0;
  			rel_info = mtu;
  			rel_msg = 1;
  		}
  		break;
46d30cb10   Kees Cook   net: ip6_gre: Dis...
548
  	}
383c1f887   Xin Long   ip6_tunnel: add t...
549
550
551
552
  	case NDISC_REDIRECT:
  		ip6_redirect(skb, net, skb->dev->ifindex, 0,
  			     sock_net_uid(net, NULL));
  		break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
553
  	}
e490d1d85   Yasuyuki Kozakai   [IPV6] IP6TUNNEL:...
554
555
556
557
558
559
560
  
  	*type = rel_type;
  	*code = rel_code;
  	*info = rel_info;
  	*msg = rel_msg;
  
  out:
2922bc8ae   Eric Dumazet   ip6tnl: convert h...
561
  	rcu_read_unlock();
e490d1d85   Yasuyuki Kozakai   [IPV6] IP6TUNNEL:...
562
563
564
565
  	return err;
  }
  
  static int
c4d3efafc   Yasuyuki Kozakai   [IPV6] IP6TUNNEL:...
566
  ip4ip6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
d5fdd6bab   Brian Haley   ipv6: Use correct...
567
  	   u8 type, u8 code, int offset, __be32 info)
c4d3efafc   Yasuyuki Kozakai   [IPV6] IP6TUNNEL:...
568
  {
704eae1f3   Al Viro   ip6_tunnel - endi...
569
  	__u32 rel_info = ntohl(info);
b71d1d426   Eric Dumazet   inet: constify ip...
570
  	const struct iphdr *eiph;
77552cfa3   Xin Long   ip6_tunnel: clean...
571
572
573
574
  	struct sk_buff *skb2;
  	int err, rel_msg = 0;
  	u8 rel_type = type;
  	u8 rel_code = code;
c4d3efafc   Yasuyuki Kozakai   [IPV6] IP6TUNNEL:...
575
  	struct rtable *rt;
31e4543db   David S. Miller   ipv4: Make caller...
576
  	struct flowi4 fl4;
c4d3efafc   Yasuyuki Kozakai   [IPV6] IP6TUNNEL:...
577

502b09356   Yasuyuki Kozakai   [IPV6] IP6TUNNEL:...
578
579
  	err = ip6_tnl_err(skb, IPPROTO_IPIP, opt, &rel_type, &rel_code,
  			  &rel_msg, &rel_info, offset);
c4d3efafc   Yasuyuki Kozakai   [IPV6] IP6TUNNEL:...
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
  	if (err < 0)
  		return err;
  
  	if (rel_msg == 0)
  		return 0;
  
  	switch (rel_type) {
  	case ICMPV6_DEST_UNREACH:
  		if (rel_code != ICMPV6_ADDR_UNREACH)
  			return 0;
  		rel_type = ICMP_DEST_UNREACH;
  		rel_code = ICMP_HOST_UNREACH;
  		break;
  	case ICMPV6_PKT_TOOBIG:
  		if (rel_code != 0)
  			return 0;
  		rel_type = ICMP_DEST_UNREACH;
  		rel_code = ICMP_FRAG_NEEDED;
  		break;
  	default:
  		return 0;
  	}
  
  	if (!pskb_may_pull(skb, offset + sizeof(struct iphdr)))
  		return 0;
  
  	skb2 = skb_clone(skb, GFP_ATOMIC);
  	if (!skb2)
  		return 0;
adf30907d   Eric Dumazet   net: skb->dst acc...
609
  	skb_dst_drop(skb2);
c4d3efafc   Yasuyuki Kozakai   [IPV6] IP6TUNNEL:...
610
  	skb_pull(skb2, offset);
c1d2bbe1c   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
611
  	skb_reset_network_header(skb2);
eddc9ec53   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
612
  	eiph = ip_hdr(skb2);
c4d3efafc   Yasuyuki Kozakai   [IPV6] IP6TUNNEL:...
613
614
  
  	/* Try to guess incoming interface */
77552cfa3   Xin Long   ip6_tunnel: clean...
615
616
  	rt = ip_route_output_ports(dev_net(skb->dev), &fl4, NULL, eiph->saddr,
  				   0, 0, 0, IPPROTO_IPIP, RT_TOS(eiph->tos), 0);
b23dd4fe4   David S. Miller   ipv4: Make output...
617
  	if (IS_ERR(rt))
c4d3efafc   Yasuyuki Kozakai   [IPV6] IP6TUNNEL:...
618
  		goto out;
d8d1f30b9   Changli Gao   net-next: remove ...
619
  	skb2->dev = rt->dst.dev;
77552cfa3   Xin Long   ip6_tunnel: clean...
620
  	ip_rt_put(rt);
c4d3efafc   Yasuyuki Kozakai   [IPV6] IP6TUNNEL:...
621
622
623
  
  	/* route "incoming" packet */
  	if (rt->rt_flags & RTCF_LOCAL) {
31e4543db   David S. Miller   ipv4: Make caller...
624
  		rt = ip_route_output_ports(dev_net(skb->dev), &fl4, NULL,
77552cfa3   Xin Long   ip6_tunnel: clean...
625
626
  					   eiph->daddr, eiph->saddr, 0, 0,
  					   IPPROTO_IPIP, RT_TOS(eiph->tos), 0);
b2e54b09a   Sheena Mira-ato   ip6_tunnel: Match...
627
  		if (IS_ERR(rt) || rt->dst.dev->type != ARPHRD_TUNNEL6) {
b23dd4fe4   David S. Miller   ipv4: Make output...
628
629
  			if (!IS_ERR(rt))
  				ip_rt_put(rt);
c4d3efafc   Yasuyuki Kozakai   [IPV6] IP6TUNNEL:...
630
631
  			goto out;
  		}
b23dd4fe4   David S. Miller   ipv4: Make output...
632
  		skb_dst_set(skb2, &rt->dst);
c4d3efafc   Yasuyuki Kozakai   [IPV6] IP6TUNNEL:...
633
  	} else {
c4d3efafc   Yasuyuki Kozakai   [IPV6] IP6TUNNEL:...
634
635
  		if (ip_route_input(skb2, eiph->daddr, eiph->saddr, eiph->tos,
  				   skb2->dev) ||
b2e54b09a   Sheena Mira-ato   ip6_tunnel: Match...
636
  		    skb_dst(skb2)->dev->type != ARPHRD_TUNNEL6)
c4d3efafc   Yasuyuki Kozakai   [IPV6] IP6TUNNEL:...
637
638
639
640
641
  			goto out;
  	}
  
  	/* change mtu on this route */
  	if (rel_type == ICMP_DEST_UNREACH && rel_code == ICMP_FRAG_NEEDED) {
adf30907d   Eric Dumazet   net: skb->dst acc...
642
  		if (rel_info > dst_mtu(skb_dst(skb2)))
c4d3efafc   Yasuyuki Kozakai   [IPV6] IP6TUNNEL:...
643
  			goto out;
7a1592bcb   Hangbin Liu   tunnel: do not co...
644
  		skb_dst_update_pmtu_no_confirm(skb2, rel_info);
c4d3efafc   Yasuyuki Kozakai   [IPV6] IP6TUNNEL:...
645
  	}
704eae1f3   Al Viro   ip6_tunnel - endi...
646
  	icmp_send(skb2, rel_type, rel_code, htonl(rel_info));
c4d3efafc   Yasuyuki Kozakai   [IPV6] IP6TUNNEL:...
647
648
649
650
651
652
653
  
  out:
  	kfree_skb(skb2);
  	return 0;
  }
  
  static int
e490d1d85   Yasuyuki Kozakai   [IPV6] IP6TUNNEL:...
654
  ip6ip6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
d5fdd6bab   Brian Haley   ipv6: Use correct...
655
  	   u8 type, u8 code, int offset, __be32 info)
e490d1d85   Yasuyuki Kozakai   [IPV6] IP6TUNNEL:...
656
  {
77552cfa3   Xin Long   ip6_tunnel: clean...
657
658
  	__u32 rel_info = ntohl(info);
  	int err, rel_msg = 0;
d5fdd6bab   Brian Haley   ipv6: Use correct...
659
660
  	u8 rel_type = type;
  	u8 rel_code = code;
e490d1d85   Yasuyuki Kozakai   [IPV6] IP6TUNNEL:...
661

502b09356   Yasuyuki Kozakai   [IPV6] IP6TUNNEL:...
662
663
  	err = ip6_tnl_err(skb, IPPROTO_IPV6, opt, &rel_type, &rel_code,
  			  &rel_msg, &rel_info, offset);
e490d1d85   Yasuyuki Kozakai   [IPV6] IP6TUNNEL:...
664
665
666
667
  	if (err < 0)
  		return err;
  
  	if (rel_msg && pskb_may_pull(skb, offset + sizeof(struct ipv6hdr))) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
668
669
  		struct rt6_info *rt;
  		struct sk_buff *skb2 = skb_clone(skb, GFP_ATOMIC);
305d4b3ce   Ville Nuorvala   [IPV6]: Allow lin...
670

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
671
  		if (!skb2)
e490d1d85   Yasuyuki Kozakai   [IPV6] IP6TUNNEL:...
672
  			return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
673

adf30907d   Eric Dumazet   net: skb->dst acc...
674
  		skb_dst_drop(skb2);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
675
  		skb_pull(skb2, offset);
c1d2bbe1c   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
676
  		skb_reset_network_header(skb2);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
677
678
  
  		/* Try to guess incoming interface */
2f7f54b72   Pavel Emelyanov   [IP6TUNNEL]: Use ...
679
  		rt = rt6_lookup(dev_net(skb->dev), &ipv6_hdr(skb2)->saddr,
b75cc8f90   David Ahern   net/ipv6: Pass sk...
680
  				NULL, 0, skb2, 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
681

d19185428   David S. Miller   ipv6: Kill rt6i_d...
682
683
  		if (rt && rt->dst.dev)
  			skb2->dev = rt->dst.dev;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
684

3ffe533c8   Alexey Dobriyan   ipv6: drop unused...
685
  		icmpv6_send(skb2, rel_type, rel_code, rel_info);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
686

94e187c01   Amerigo Wang   ipv6: introduce i...
687
  		ip6_rt_put(rt);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
688
689
690
  
  		kfree_skb(skb2);
  	}
e490d1d85   Yasuyuki Kozakai   [IPV6] IP6TUNNEL:...
691
692
  
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
693
  }
f200e98d9   Vadim Fedorenko   ip6_tunnel: add g...
694
695
696
697
698
699
700
701
702
703
704
705
706
  static int
  mplsip6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
  	    u8 type, u8 code, int offset, __be32 info)
  {
  	__u32 rel_info = ntohl(info);
  	int err, rel_msg = 0;
  	u8 rel_type = type;
  	u8 rel_code = code;
  
  	err = ip6_tnl_err(skb, IPPROTO_MPLS, opt, &rel_type, &rel_code,
  			  &rel_msg, &rel_info, offset);
  	return err;
  }
f4e0b4c5e   Nicolas Dichtel   ip6tnl/sit: drop ...
707
708
709
  static int ip4ip6_dscp_ecn_decapsulate(const struct ip6_tnl *t,
  				       const struct ipv6hdr *ipv6h,
  				       struct sk_buff *skb)
c4d3efafc   Yasuyuki Kozakai   [IPV6] IP6TUNNEL:...
710
711
712
713
  {
  	__u8 dsfield = ipv6_get_dsfield(ipv6h) & ~INET_ECN_MASK;
  
  	if (t->parms.flags & IP6_TNL_F_RCV_DSCP_COPY)
eddc9ec53   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
714
  		ipv4_change_dsfield(ip_hdr(skb), INET_ECN_MASK, dsfield);
c4d3efafc   Yasuyuki Kozakai   [IPV6] IP6TUNNEL:...
715

f4e0b4c5e   Nicolas Dichtel   ip6tnl/sit: drop ...
716
  	return IP6_ECN_decapsulate(ipv6h, skb);
c4d3efafc   Yasuyuki Kozakai   [IPV6] IP6TUNNEL:...
717
  }
f4e0b4c5e   Nicolas Dichtel   ip6tnl/sit: drop ...
718
719
720
  static int ip6ip6_dscp_ecn_decapsulate(const struct ip6_tnl *t,
  				       const struct ipv6hdr *ipv6h,
  				       struct sk_buff *skb)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
721
  {
8359925be   Yasuyuki Kozakai   [IPV6] IP6TUNNEL:...
722
  	if (t->parms.flags & IP6_TNL_F_RCV_DSCP_COPY)
29bb43b4e   Herbert Xu   [INET]: Give oute...
723
  		ipv6_copy_dscp(ipv6_get_dsfield(ipv6h), ipv6_hdr(skb));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
724

f4e0b4c5e   Nicolas Dichtel   ip6tnl/sit: drop ...
725
  	return IP6_ECN_decapsulate(ipv6h, skb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
726
  }
8359925be   Yasuyuki Kozakai   [IPV6] IP6TUNNEL:...
727

f200e98d9   Vadim Fedorenko   ip6_tunnel: add g...
728
729
730
731
732
733
734
  static inline int mplsip6_dscp_ecn_decapsulate(const struct ip6_tnl *t,
  					       const struct ipv6hdr *ipv6h,
  					       struct sk_buff *skb)
  {
  	/* ECN is not supported in AF_MPLS */
  	return 0;
  }
c12b395a4   xeb@mail.ru   gre: Support GRE ...
735
  __u32 ip6_tnl_get_cap(struct ip6_tnl *t,
d0087b29f   Ville Nuorvala   ipv6_tunnel: Allo...
736
737
738
  			     const struct in6_addr *laddr,
  			     const struct in6_addr *raddr)
  {
c12b395a4   xeb@mail.ru   gre: Support GRE ...
739
  	struct __ip6_tnl_parm *p = &t->parms;
d0087b29f   Ville Nuorvala   ipv6_tunnel: Allo...
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
  	int ltype = ipv6_addr_type(laddr);
  	int rtype = ipv6_addr_type(raddr);
  	__u32 flags = 0;
  
  	if (ltype == IPV6_ADDR_ANY || rtype == IPV6_ADDR_ANY) {
  		flags = IP6_TNL_F_CAP_PER_PACKET;
  	} else if (ltype & (IPV6_ADDR_UNICAST|IPV6_ADDR_MULTICAST) &&
  		   rtype & (IPV6_ADDR_UNICAST|IPV6_ADDR_MULTICAST) &&
  		   !((ltype|rtype) & IPV6_ADDR_LOOPBACK) &&
  		   (!((ltype|rtype) & IPV6_ADDR_LINKLOCAL) || p->link)) {
  		if (ltype&IPV6_ADDR_UNICAST)
  			flags |= IP6_TNL_F_CAP_XMIT;
  		if (rtype&IPV6_ADDR_UNICAST)
  			flags |= IP6_TNL_F_CAP_RCV;
  	}
  	return flags;
  }
c12b395a4   xeb@mail.ru   gre: Support GRE ...
757
  EXPORT_SYMBOL(ip6_tnl_get_cap);
d0087b29f   Ville Nuorvala   ipv6_tunnel: Allo...
758

f1a28eab2   Eric Dumazet   ip6tnl: less dev_...
759
  /* called with rcu_read_lock() */
c12b395a4   xeb@mail.ru   gre: Support GRE ...
760
  int ip6_tnl_rcv_ctl(struct ip6_tnl *t,
d0087b29f   Ville Nuorvala   ipv6_tunnel: Allo...
761
762
  				  const struct in6_addr *laddr,
  				  const struct in6_addr *raddr)
09c6bbf09   Ville Nuorvala   [IPV6]: Do mandat...
763
  {
c12b395a4   xeb@mail.ru   gre: Support GRE ...
764
  	struct __ip6_tnl_parm *p = &t->parms;
09c6bbf09   Ville Nuorvala   [IPV6]: Do mandat...
765
  	int ret = 0;
0bd876282   Nicolas Dichtel   ip6tnl: add x-net...
766
  	struct net *net = t->net;
09c6bbf09   Ville Nuorvala   [IPV6]: Do mandat...
767

d0087b29f   Ville Nuorvala   ipv6_tunnel: Allo...
768
769
770
  	if ((p->flags & IP6_TNL_F_CAP_RCV) ||
  	    ((p->flags & IP6_TNL_F_CAP_PER_PACKET) &&
  	     (ip6_tnl_get_cap(t, laddr, raddr) & IP6_TNL_F_CAP_RCV))) {
1ab1457c4   YOSHIFUJI Hideaki   [NET] IPV6: Fix w...
771
  		struct net_device *ldev = NULL;
09c6bbf09   Ville Nuorvala   [IPV6]: Do mandat...
772
773
  
  		if (p->link)
f1a28eab2   Eric Dumazet   ip6tnl: less dev_...
774
  			ldev = dev_get_by_index_rcu(net, p->link);
09c6bbf09   Ville Nuorvala   [IPV6]: Do mandat...
775

d0087b29f   Ville Nuorvala   ipv6_tunnel: Allo...
776
  		if ((ipv6_addr_is_multicast(laddr) ||
232378e8d   David Ahern   net/ipv6: Change ...
777
778
  		     likely(ipv6_chk_addr_and_flags(net, laddr, ldev, false,
  						    0, IFA_F_TENTATIVE))) &&
908d140a8   Shmulik Ladkani   ip6_tunnel: Allow...
779
  		    ((p->flags & IP6_TNL_F_ALLOW_LOCAL_REMOTE) ||
232378e8d   David Ahern   net/ipv6: Change ...
780
781
  		     likely(!ipv6_chk_addr_and_flags(net, raddr, ldev, true,
  						     0, IFA_F_TENTATIVE))))
09c6bbf09   Ville Nuorvala   [IPV6]: Do mandat...
782
  			ret = 1;
09c6bbf09   Ville Nuorvala   [IPV6]: Do mandat...
783
784
785
  	}
  	return ret;
  }
c12b395a4   xeb@mail.ru   gre: Support GRE ...
786
  EXPORT_SYMBOL_GPL(ip6_tnl_rcv_ctl);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
787

0d3c703a9   Tom Herbert   ipv6: Cleanup IPv...
788
789
790
791
792
793
794
  static int __ip6_tnl_rcv(struct ip6_tnl *tunnel, struct sk_buff *skb,
  			 const struct tnl_ptk_info *tpi,
  			 struct metadata_dst *tun_dst,
  			 int (*dscp_ecn_decapsulate)(const struct ip6_tnl *t,
  						const struct ipv6hdr *ipv6h,
  						struct sk_buff *skb),
  			 bool log_ecn_err)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
795
  {
0d3c703a9   Tom Herbert   ipv6: Cleanup IPv...
796
  	struct pcpu_sw_netstats *tstats;
b71d1d426   Eric Dumazet   inet: constify ip...
797
  	const struct ipv6hdr *ipv6h = ipv6_hdr(skb);
f4e0b4c5e   Nicolas Dichtel   ip6tnl/sit: drop ...
798
  	int err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
799

0d3c703a9   Tom Herbert   ipv6: Cleanup IPv...
800
801
802
803
804
805
806
807
  	if ((!(tpi->flags & TUNNEL_CSUM) &&
  	     (tunnel->parms.i_flags & TUNNEL_CSUM)) ||
  	    ((tpi->flags & TUNNEL_CSUM) &&
  	     !(tunnel->parms.i_flags & TUNNEL_CSUM))) {
  		tunnel->dev->stats.rx_crc_errors++;
  		tunnel->dev->stats.rx_errors++;
  		goto drop;
  	}
8560f2266   Eric Dumazet   ip6tnl: percpu st...
808

0d3c703a9   Tom Herbert   ipv6: Cleanup IPv...
809
810
811
812
813
814
815
  	if (tunnel->parms.i_flags & TUNNEL_SEQ) {
  		if (!(tpi->flags & TUNNEL_SEQ) ||
  		    (tunnel->i_seqno &&
  		     (s32)(ntohl(tpi->seq) - tunnel->i_seqno) < 0)) {
  			tunnel->dev->stats.rx_fifo_errors++;
  			tunnel->dev->stats.rx_errors++;
  			goto drop;
502b09356   Yasuyuki Kozakai   [IPV6] IP6TUNNEL:...
816
  		}
0d3c703a9   Tom Herbert   ipv6: Cleanup IPv...
817
818
  		tunnel->i_seqno = ntohl(tpi->seq) + 1;
  	}
502b09356   Yasuyuki Kozakai   [IPV6] IP6TUNNEL:...
819

0d3c703a9   Tom Herbert   ipv6: Cleanup IPv...
820
  	skb->protocol = tpi->proto;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
821

0d3c703a9   Tom Herbert   ipv6: Cleanup IPv...
822
823
824
825
826
827
  	/* Warning: All skb pointers will be invalidated! */
  	if (tunnel->dev->type == ARPHRD_ETHER) {
  		if (!pskb_may_pull(skb, ETH_HLEN)) {
  			tunnel->dev->stats.rx_length_errors++;
  			tunnel->dev->stats.rx_errors++;
  			goto drop;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
828
  		}
0d3c703a9   Tom Herbert   ipv6: Cleanup IPv...
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
  
  		ipv6h = ipv6_hdr(skb);
  		skb->protocol = eth_type_trans(skb, tunnel->dev);
  		skb_postpull_rcsum(skb, eth_hdr(skb), ETH_HLEN);
  	} else {
  		skb->dev = tunnel->dev;
  	}
  
  	skb_reset_network_header(skb);
  	memset(skb->cb, 0, sizeof(struct inet6_skb_parm));
  
  	__skb_tunnel_rx(skb, tunnel->dev, tunnel->net);
  
  	err = dscp_ecn_decapsulate(tunnel, ipv6h, skb);
  	if (unlikely(err)) {
  		if (log_ecn_err)
  			net_info_ratelimited("non-ECT from %pI6 with DS=%#x
  ",
  					     &ipv6h->saddr,
  					     ipv6_get_dsfield(ipv6h));
  		if (err > 1) {
  			++tunnel->dev->stats.rx_frame_errors;
  			++tunnel->dev->stats.rx_errors;
  			goto drop;
f4e0b4c5e   Nicolas Dichtel   ip6tnl/sit: drop ...
853
  		}
0d3c703a9   Tom Herbert   ipv6: Cleanup IPv...
854
  	}
f4e0b4c5e   Nicolas Dichtel   ip6tnl/sit: drop ...
855

0d3c703a9   Tom Herbert   ipv6: Cleanup IPv...
856
857
858
859
860
  	tstats = this_cpu_ptr(tunnel->dev->tstats);
  	u64_stats_update_begin(&tstats->syncp);
  	tstats->rx_packets++;
  	tstats->rx_bytes += skb->len;
  	u64_stats_update_end(&tstats->syncp);
8560f2266   Eric Dumazet   ip6tnl: percpu st...
861

0d3c703a9   Tom Herbert   ipv6: Cleanup IPv...
862
  	skb_scrub_packet(skb, !net_eq(tunnel->net, dev_net(tunnel->dev)));
8990f468a   Eric Dumazet   net: rx_dropped a...
863

8d79266bc   Alexei Starovoitov   ip6_tunnel: add c...
864
865
  	if (tun_dst)
  		skb_dst_set(skb, (struct dst_entry *)tun_dst);
0d3c703a9   Tom Herbert   ipv6: Cleanup IPv...
866
867
868
869
  	gro_cells_receive(&tunnel->gro_cells, skb);
  	return 0;
  
  drop:
f1925ca50   Haishuang Yan   ip6_tunnel: fix p...
870
871
  	if (tun_dst)
  		dst_release((struct dst_entry *)tun_dst);
0d3c703a9   Tom Herbert   ipv6: Cleanup IPv...
872
873
874
875
876
877
878
879
880
  	kfree_skb(skb);
  	return 0;
  }
  
  int ip6_tnl_rcv(struct ip6_tnl *t, struct sk_buff *skb,
  		const struct tnl_ptk_info *tpi,
  		struct metadata_dst *tun_dst,
  		bool log_ecn_err)
  {
272502fcb   Mark Tomlinson   gre6: Fix recepti...
881
882
883
884
885
886
887
888
889
  	int (*dscp_ecn_decapsulate)(const struct ip6_tnl *t,
  				    const struct ipv6hdr *ipv6h,
  				    struct sk_buff *skb);
  
  	dscp_ecn_decapsulate = ip6ip6_dscp_ecn_decapsulate;
  	if (tpi->proto == htons(ETH_P_IP))
  		dscp_ecn_decapsulate = ip4ip6_dscp_ecn_decapsulate;
  
  	return __ip6_tnl_rcv(t, skb, tpi, tun_dst, dscp_ecn_decapsulate,
0d3c703a9   Tom Herbert   ipv6: Cleanup IPv...
890
891
892
893
894
895
896
897
898
899
900
901
902
  			     log_ecn_err);
  }
  EXPORT_SYMBOL(ip6_tnl_rcv);
  
  static const struct tnl_ptk_info tpi_v6 = {
  	/* no tunnel info required for ipxip6. */
  	.proto = htons(ETH_P_IPV6),
  };
  
  static const struct tnl_ptk_info tpi_v4 = {
  	/* no tunnel info required for ipxip6. */
  	.proto = htons(ETH_P_IP),
  };
f200e98d9   Vadim Fedorenko   ip6_tunnel: add g...
903
904
905
906
  static const struct tnl_ptk_info tpi_mpls = {
  	/* no tunnel info required for mplsip6. */
  	.proto = htons(ETH_P_MPLS_UC),
  };
0d3c703a9   Tom Herbert   ipv6: Cleanup IPv...
907
908
909
910
911
912
913
914
  static int ipxip6_rcv(struct sk_buff *skb, u8 ipproto,
  		      const struct tnl_ptk_info *tpi,
  		      int (*dscp_ecn_decapsulate)(const struct ip6_tnl *t,
  						  const struct ipv6hdr *ipv6h,
  						  struct sk_buff *skb))
  {
  	struct ip6_tnl *t;
  	const struct ipv6hdr *ipv6h = ipv6_hdr(skb);
8d79266bc   Alexei Starovoitov   ip6_tunnel: add c...
915
  	struct metadata_dst *tun_dst = NULL;
0d3c703a9   Tom Herbert   ipv6: Cleanup IPv...
916
917
918
  	int ret = -1;
  
  	rcu_read_lock();
5fdcce211   William Dauchy   net, ip6_tunnel: ...
919
  	t = ip6_tnl_lookup(dev_net(skb->dev), skb->dev->ifindex, &ipv6h->saddr, &ipv6h->daddr);
0d3c703a9   Tom Herbert   ipv6: Cleanup IPv...
920
921
  
  	if (t) {
6aa7de059   Mark Rutland   locking/atomics: ...
922
  		u8 tproto = READ_ONCE(t->parms.proto);
0d3c703a9   Tom Herbert   ipv6: Cleanup IPv...
923
924
925
926
927
  
  		if (tproto != ipproto && tproto != 0)
  			goto drop;
  		if (!xfrm6_policy_check(NULL, XFRM_POLICY_IN, skb))
  			goto drop;
cbb49697d   Eric Dumazet   ipv6: tunnels: fi...
928
  		ipv6h = ipv6_hdr(skb);
0d3c703a9   Tom Herbert   ipv6: Cleanup IPv...
929
930
931
932
  		if (!ip6_tnl_rcv_ctl(t, &ipv6h->daddr, &ipv6h->saddr))
  			goto drop;
  		if (iptunnel_pull_header(skb, 0, tpi->proto, false))
  			goto drop;
8d79266bc   Alexei Starovoitov   ip6_tunnel: add c...
933
934
935
  		if (t->parms.collect_md) {
  			tun_dst = ipv6_tun_rx_dst(skb, 0, 0, 0);
  			if (!tun_dst)
74c4b656c   Nikita V. Shirokov   adding missing rc...
936
  				goto drop;
8d79266bc   Alexei Starovoitov   ip6_tunnel: add c...
937
938
  		}
  		ret = __ip6_tnl_rcv(t, skb, tpi, tun_dst, dscp_ecn_decapsulate,
0d3c703a9   Tom Herbert   ipv6: Cleanup IPv...
939
  				    log_ecn_error);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
940
  	}
0d3c703a9   Tom Herbert   ipv6: Cleanup IPv...
941

2922bc8ae   Eric Dumazet   ip6tnl: convert h...
942
  	rcu_read_unlock();
50fba2aa7   Herbert Xu   [INET]: Move no-t...
943

0d3c703a9   Tom Herbert   ipv6: Cleanup IPv...
944
945
946
947
  	return ret;
  
  drop:
  	rcu_read_unlock();
50fba2aa7   Herbert Xu   [INET]: Move no-t...
948
949
  	kfree_skb(skb);
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
950
  }
c4d3efafc   Yasuyuki Kozakai   [IPV6] IP6TUNNEL:...
951
952
  static int ip4ip6_rcv(struct sk_buff *skb)
  {
ca4aa976f   Nicolas Dichtel   ipv6: fix 4in6 tu...
953
  	return ipxip6_rcv(skb, IPPROTO_IPIP, &tpi_v4,
0d3c703a9   Tom Herbert   ipv6: Cleanup IPv...
954
  			  ip4ip6_dscp_ecn_decapsulate);
c4d3efafc   Yasuyuki Kozakai   [IPV6] IP6TUNNEL:...
955
  }
8359925be   Yasuyuki Kozakai   [IPV6] IP6TUNNEL:...
956
957
  static int ip6ip6_rcv(struct sk_buff *skb)
  {
0d3c703a9   Tom Herbert   ipv6: Cleanup IPv...
958
959
  	return ipxip6_rcv(skb, IPPROTO_IPV6, &tpi_v6,
  			  ip6ip6_dscp_ecn_decapsulate);
8359925be   Yasuyuki Kozakai   [IPV6] IP6TUNNEL:...
960
  }
f200e98d9   Vadim Fedorenko   ip6_tunnel: add g...
961
962
963
964
965
  static int mplsip6_rcv(struct sk_buff *skb)
  {
  	return ipxip6_rcv(skb, IPPROTO_MPLS, &tpi_mpls,
  			  mplsip6_dscp_ecn_decapsulate);
  }
6fb32ddeb   Ville Nuorvala   [IPV6]: Don't all...
966
967
968
969
  struct ipv6_tel_txoption {
  	struct ipv6_txoptions ops;
  	__u8 dst_opt[8];
  };
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
970

6fb32ddeb   Ville Nuorvala   [IPV6]: Don't all...
971
972
973
  static void init_tel_txopt(struct ipv6_tel_txoption *opt, __u8 encap_limit)
  {
  	memset(opt, 0, sizeof(struct ipv6_tel_txoption));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
974

6fb32ddeb   Ville Nuorvala   [IPV6]: Don't all...
975
976
977
978
979
  	opt->dst_opt[2] = IPV6_TLV_TNL_ENCAP_LIMIT;
  	opt->dst_opt[3] = 1;
  	opt->dst_opt[4] = encap_limit;
  	opt->dst_opt[5] = IPV6_TLV_PADN;
  	opt->dst_opt[6] = 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
980

89a23c8b5   Craig Gallek   ip6_tunnel: Fix m...
981
  	opt->ops.dst1opt = (struct ipv6_opt_hdr *) opt->dst_opt;
6fb32ddeb   Ville Nuorvala   [IPV6]: Don't all...
982
  	opt->ops.opt_nflen = 8;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
983
984
985
  }
  
  /**
3144581cb   Yasuyuki Kozakai   [IPV6] IP6TUNNEL:...
986
   * ip6_tnl_addr_conflict - compare packet addresses to tunnel's own
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
987
   *   @t: the outgoing tunnel device
1ab1457c4   YOSHIFUJI Hideaki   [NET] IPV6: Fix w...
988
   *   @hdr: IPv6 header from the incoming packet
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
989
990
   *
   * Description:
1ab1457c4   YOSHIFUJI Hideaki   [NET] IPV6: Fix w...
991
   *   Avoid trivial tunneling loop by checking that tunnel exit-point
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
992
993
   *   doesn't match source of incoming packet.
   *
1ab1457c4   YOSHIFUJI Hideaki   [NET] IPV6: Fix w...
994
   * Return:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
995
996
997
   *   1 if conflict,
   *   0 else
   **/
92113bfde   Eric Dumazet   ipv6: bool conver...
998
  static inline bool
b71d1d426   Eric Dumazet   inet: constify ip...
999
  ip6_tnl_addr_conflict(const struct ip6_tnl *t, const struct ipv6hdr *hdr)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1000
1001
1002
  {
  	return ipv6_addr_equal(&t->parms.raddr, &hdr->saddr);
  }
d50051407   Steffen Klassert   ipv6: Allow sendi...
1003
1004
1005
  int ip6_tnl_xmit_ctl(struct ip6_tnl *t,
  		     const struct in6_addr *laddr,
  		     const struct in6_addr *raddr)
09c6bbf09   Ville Nuorvala   [IPV6]: Do mandat...
1006
  {
c12b395a4   xeb@mail.ru   gre: Support GRE ...
1007
  	struct __ip6_tnl_parm *p = &t->parms;
09c6bbf09   Ville Nuorvala   [IPV6]: Do mandat...
1008
  	int ret = 0;
0bd876282   Nicolas Dichtel   ip6tnl: add x-net...
1009
  	struct net *net = t->net;
09c6bbf09   Ville Nuorvala   [IPV6]: Do mandat...
1010

6712abc16   William Tu   ip6_gre: add ip6 ...
1011
1012
  	if (t->parms.collect_md)
  		return 1;
d50051407   Steffen Klassert   ipv6: Allow sendi...
1013
1014
1015
  	if ((p->flags & IP6_TNL_F_CAP_XMIT) ||
  	    ((p->flags & IP6_TNL_F_CAP_PER_PACKET) &&
  	     (ip6_tnl_get_cap(t, laddr, raddr) & IP6_TNL_F_CAP_XMIT))) {
09c6bbf09   Ville Nuorvala   [IPV6]: Do mandat...
1016
  		struct net_device *ldev = NULL;
f1a28eab2   Eric Dumazet   ip6tnl: less dev_...
1017
  		rcu_read_lock();
09c6bbf09   Ville Nuorvala   [IPV6]: Do mandat...
1018
  		if (p->link)
f1a28eab2   Eric Dumazet   ip6tnl: less dev_...
1019
  			ldev = dev_get_by_index_rcu(net, p->link);
09c6bbf09   Ville Nuorvala   [IPV6]: Do mandat...
1020

232378e8d   David Ahern   net/ipv6: Change ...
1021
1022
  		if (unlikely(!ipv6_chk_addr_and_flags(net, laddr, ldev, false,
  						      0, IFA_F_TENTATIVE)))
f32138319   Joe Perches   net: ipv6: Standa...
1023
1024
1025
  			pr_warn("%s xmit: Local address not yet configured!
  ",
  				p->name);
908d140a8   Shmulik Ladkani   ip6_tunnel: Allow...
1026
1027
  		else if (!(p->flags & IP6_TNL_F_ALLOW_LOCAL_REMOTE) &&
  			 !ipv6_addr_is_multicast(raddr) &&
232378e8d   David Ahern   net/ipv6: Change ...
1028
1029
  			 unlikely(ipv6_chk_addr_and_flags(net, raddr, ldev,
  							  true, 0, IFA_F_TENTATIVE)))
f32138319   Joe Perches   net: ipv6: Standa...
1030
1031
1032
  			pr_warn("%s xmit: Routing loop! Remote address found on this node!
  ",
  				p->name);
09c6bbf09   Ville Nuorvala   [IPV6]: Do mandat...
1033
1034
  		else
  			ret = 1;
f1a28eab2   Eric Dumazet   ip6tnl: less dev_...
1035
  		rcu_read_unlock();
09c6bbf09   Ville Nuorvala   [IPV6]: Do mandat...
1036
1037
1038
  	}
  	return ret;
  }
c12b395a4   xeb@mail.ru   gre: Support GRE ...
1039
  EXPORT_SYMBOL_GPL(ip6_tnl_xmit_ctl);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1040
  /**
8eb30be03   Tom Herbert   ipv6: Create ip6_...
1041
   * ip6_tnl_xmit - encapsulate packet and send
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1042
   *   @skb: the outgoing socket buffer
1ab1457c4   YOSHIFUJI Hideaki   [NET] IPV6: Fix w...
1043
   *   @dev: the outgoing tunnel device
61ec2aec2   Yasuyuki Kozakai   [IPV6] IP6TUNNEL:...
1044
   *   @dsfield: dscp code for outer header
8eb30be03   Tom Herbert   ipv6: Create ip6_...
1045
   *   @fl6: flow of tunneled packet
61ec2aec2   Yasuyuki Kozakai   [IPV6] IP6TUNNEL:...
1046
1047
   *   @encap_limit: encapsulation limit
   *   @pmtu: Path MTU is stored if packet is too big
8eb30be03   Tom Herbert   ipv6: Create ip6_...
1048
   *   @proto: next header value
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1049
1050
1051
1052
1053
   *
   * Description:
   *   Build new header and do some sanity checks on the packet before sending
   *   it.
   *
1ab1457c4   YOSHIFUJI Hideaki   [NET] IPV6: Fix w...
1054
   * Return:
c4d3efafc   Yasuyuki Kozakai   [IPV6] IP6TUNNEL:...
1055
   *   0 on success
61ec2aec2   Yasuyuki Kozakai   [IPV6] IP6TUNNEL:...
1056
1057
   *   -1 fail
   *   %-EMSGSIZE message too big. return mtu in this case.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1058
   **/
8eb30be03   Tom Herbert   ipv6: Create ip6_...
1059
1060
1061
  int ip6_tnl_xmit(struct sk_buff *skb, struct net_device *dev, __u8 dsfield,
  		 struct flowi6 *fl6, int encap_limit, __u32 *pmtu,
  		 __u8 proto)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1062
  {
2941a4863   Patrick McHardy   [NET]: Convert ne...
1063
  	struct ip6_tnl *t = netdev_priv(dev);
0bd876282   Nicolas Dichtel   ip6tnl: add x-net...
1064
  	struct net *net = t->net;
3dca02af3   Pavel Emelyanov   ip6tnl: Use on-de...
1065
  	struct net_device_stats *stats = &t->dev->stats;
199ab00f3   WANG Cong   ipv6: check skb->...
1066
  	struct ipv6hdr *ipv6h;
6fb32ddeb   Ville Nuorvala   [IPV6]: Don't all...
1067
  	struct ipv6_tel_txoption opt;
d24f22f3d   Eric Dumazet   ip6_tunnel: add o...
1068
  	struct dst_entry *dst = NULL, *ndst = NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1069
1070
  	struct net_device *tdev;
  	int mtu;
d41bb33ba   Xin Long   ip6_tunnel: updat...
1071
  	unsigned int eth_hlen = t->dev->type == ARPHRD_ETHER ? ETH_HLEN : 0;
058214a4d   Tom Herbert   ip6_tun: Add infr...
1072
1073
  	unsigned int psh_hlen = sizeof(struct ipv6hdr) + t->encap_hlen;
  	unsigned int max_headroom = psh_hlen;
b5c2d4954   Paolo Abeni   ip6_tunnel: disab...
1074
  	bool use_cache = false;
8d79266bc   Alexei Starovoitov   ip6_tunnel: add c...
1075
  	u8 hop_limit;
61ec2aec2   Yasuyuki Kozakai   [IPV6] IP6TUNNEL:...
1076
  	int err = -1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1077

8d79266bc   Alexei Starovoitov   ip6_tunnel: add c...
1078
1079
1080
1081
1082
1083
  	if (t->parms.collect_md) {
  		hop_limit = skb_tunnel_info(skb)->key.ttl;
  		goto route_lookup;
  	} else {
  		hop_limit = t->parms.hop_limit;
  	}
ea3dc9601   Steffen Klassert   ip6_tunnel: Add s...
1084
1085
  	/* NBMA tunnel */
  	if (ipv6_addr_any(&t->parms.raddr)) {
199ab00f3   WANG Cong   ipv6: check skb->...
1086
1087
1088
1089
  		if (skb->protocol == htons(ETH_P_IPV6)) {
  			struct in6_addr *addr6;
  			struct neighbour *neigh;
  			int addr_type;
ea3dc9601   Steffen Klassert   ip6_tunnel: Add s...
1090

199ab00f3   WANG Cong   ipv6: check skb->...
1091
1092
  			if (!skb_dst(skb))
  				goto tx_err_link_failure;
ea3dc9601   Steffen Klassert   ip6_tunnel: Add s...
1093

199ab00f3   WANG Cong   ipv6: check skb->...
1094
1095
1096
1097
  			neigh = dst_neigh_lookup(skb_dst(skb),
  						 &ipv6_hdr(skb)->daddr);
  			if (!neigh)
  				goto tx_err_link_failure;
ea3dc9601   Steffen Klassert   ip6_tunnel: Add s...
1098

199ab00f3   WANG Cong   ipv6: check skb->...
1099
1100
  			addr6 = (struct in6_addr *)&neigh->primary_key;
  			addr_type = ipv6_addr_type(addr6);
ea3dc9601   Steffen Klassert   ip6_tunnel: Add s...
1101

199ab00f3   WANG Cong   ipv6: check skb->...
1102
1103
  			if (addr_type == IPV6_ADDR_ANY)
  				addr6 = &ipv6_hdr(skb)->daddr;
ea3dc9601   Steffen Klassert   ip6_tunnel: Add s...
1104

199ab00f3   WANG Cong   ipv6: check skb->...
1105
1106
1107
  			memcpy(&fl6->daddr, addr6, sizeof(fl6->daddr));
  			neigh_release(neigh);
  		}
23263ec86   Eli Cooper   ip6_tunnel: disab...
1108
1109
1110
1111
1112
  	} else if (t->parms.proto != 0 && !(t->parms.flags &
  					    (IP6_TNL_F_USE_ORIG_TCLASS |
  					     IP6_TNL_F_USE_ORIG_FWMARK))) {
  		/* enable the cache only if neither the outer protocol nor the
  		 * routing decision depends on the current inner header value
b5c2d4954   Paolo Abeni   ip6_tunnel: disab...
1113
1114
1115
1116
1117
  		 */
  		use_cache = true;
  	}
  
  	if (use_cache)
607f725f6   Paolo Abeni   net: replace dst_...
1118
  		dst = dst_cache_get(&t->dst_cache);
d50051407   Steffen Klassert   ipv6: Allow sendi...
1119
1120
1121
  
  	if (!ip6_tnl_xmit_ctl(t, &fl6->saddr, &fl6->daddr))
  		goto tx_err_link_failure;
89b021269   Eric Dumazet   ip6tnl: avoid tou...
1122
  	if (!dst) {
8d79266bc   Alexei Starovoitov   ip6_tunnel: add c...
1123
  route_lookup:
5f733ee68   Liam McBirnie   ip6_tunnel: fix t...
1124
1125
  		/* add dsfield to flowlabel for route lookup */
  		fl6->flowlabel = ip6_make_flowinfo(dsfield, fl6->flowlabel);
cdf3464e6   Martin KaFai Lau   ipv6: Fix dst_ent...
1126
  		dst = ip6_route_output(net, NULL, fl6);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1127

cdf3464e6   Martin KaFai Lau   ipv6: Fix dst_ent...
1128
  		if (dst->error)
a57ebc90f   Patrick McHardy   [IPV6]: Don't red...
1129
  			goto tx_err_link_failure;
cdf3464e6   Martin KaFai Lau   ipv6: Fix dst_ent...
1130
1131
1132
1133
  		dst = xfrm_lookup(net, dst, flowi6_to_flowi(fl6), NULL, 0);
  		if (IS_ERR(dst)) {
  			err = PTR_ERR(dst);
  			dst = NULL;
452edd598   David S. Miller   xfrm: Return dst ...
1134
1135
  			goto tx_err_link_failure;
  		}
3789cabaa   Shmulik Ladkani   ip6_tunnel: colle...
1136
  		if (t->parms.collect_md && ipv6_addr_any(&fl6->saddr) &&
8d79266bc   Alexei Starovoitov   ip6_tunnel: add c...
1137
1138
1139
  		    ipv6_dev_get_saddr(net, ip6_dst_idev(dst)->dev,
  				       &fl6->daddr, 0, &fl6->saddr))
  			goto tx_err_link_failure;
cdf3464e6   Martin KaFai Lau   ipv6: Fix dst_ent...
1140
  		ndst = dst;
a57ebc90f   Patrick McHardy   [IPV6]: Don't red...
1141
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1142
1143
1144
1145
1146
  
  	tdev = dst->dev;
  
  	if (tdev == dev) {
  		stats->collisions++;
e87cc4728   Joe Perches   net: Convert net_...
1147
1148
1149
  		net_warn_ratelimited("%s: Local routing loop detected!
  ",
  				     t->parms.name);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1150
1151
  		goto tx_err_dst_release;
  	}
d41bb33ba   Xin Long   ip6_tunnel: updat...
1152
  	mtu = dst_mtu(dst) - eth_hlen - psh_hlen - t->tun_hlen;
6fb32ddeb   Ville Nuorvala   [IPV6]: Don't all...
1153
  	if (encap_limit >= 0) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1154
1155
1156
  		max_headroom += 8;
  		mtu -= 8;
  	}
82a40777d   Xin Long   ip6_tunnel: use t...
1157
1158
  	mtu = max(mtu, skb->protocol == htons(ETH_P_IPV6) ?
  		       IPV6_MIN_MTU : IPV4_MIN_MTU);
c9fefa081   Xin Long   ip6_tunnel: get t...
1159

7a1592bcb   Hangbin Liu   tunnel: do not co...
1160
  	skb_dst_update_pmtu_no_confirm(skb, mtu);
d41bb33ba   Xin Long   ip6_tunnel: updat...
1161
  	if (skb->len - t->tun_hlen - eth_hlen > mtu && !skb_is_gso(skb)) {
61ec2aec2   Yasuyuki Kozakai   [IPV6] IP6TUNNEL:...
1162
1163
  		*pmtu = mtu;
  		err = -EMSGSIZE;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1164
1165
  		goto tx_err_dst_release;
  	}
8eb30be03   Tom Herbert   ipv6: Create ip6_...
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
  	if (t->err_count > 0) {
  		if (time_before(jiffies,
  				t->err_time + IP6TUNNEL_ERR_TIMEO)) {
  			t->err_count--;
  
  			dst_link_failure(skb);
  		} else {
  			t->err_count = 0;
  		}
  	}
963a88b31   Nicolas Dichtel   tunnels: harmoniz...
1176
  	skb_scrub_packet(skb, !net_eq(t->net, dev_net(dev)));
0bd876282   Nicolas Dichtel   ip6tnl: add x-net...
1177

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1178
1179
1180
1181
  	/*
  	 * Okay, now see if we can stuff it in the buffer as-is.
  	 */
  	max_headroom += LL_RESERVED_SPACE(tdev);
1ab1457c4   YOSHIFUJI Hideaki   [NET] IPV6: Fix w...
1182

cfbba49d8   Patrick McHardy   [NET]: Avoid copy...
1183
1184
  	if (skb_headroom(skb) < max_headroom || skb_shared(skb) ||
  	    (skb_cloned(skb) && !skb_clone_writable(skb, 0))) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1185
  		struct sk_buff *new_skb;
1ab1457c4   YOSHIFUJI Hideaki   [NET] IPV6: Fix w...
1186

e5d08d718   Ian Morris   ipv6: coding styl...
1187
1188
  		new_skb = skb_realloc_headroom(skb, max_headroom);
  		if (!new_skb)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1189
1190
1191
1192
  			goto tx_err_dst_release;
  
  		if (skb->sk)
  			skb_set_owner_w(new_skb, skb->sk);
9ff264492   Eric Dumazet   ip6_tunnel: dont ...
1193
  		consume_skb(skb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1194
1195
  		skb = new_skb;
  	}
cdf3464e6   Martin KaFai Lau   ipv6: Fix dst_ent...
1196

8d79266bc   Alexei Starovoitov   ip6_tunnel: add c...
1197
1198
1199
1200
  	if (t->parms.collect_md) {
  		if (t->encap.type != TUNNEL_ENCAP_NONE)
  			goto tx_err_dst_release;
  	} else {
b5c2d4954   Paolo Abeni   ip6_tunnel: disab...
1201
  		if (use_cache && ndst)
8d79266bc   Alexei Starovoitov   ip6_tunnel: add c...
1202
1203
  			dst_cache_set_ip6(&t->dst_cache, ndst, &fl6->saddr);
  	}
cdf3464e6   Martin KaFai Lau   ipv6: Fix dst_ent...
1204
  	skb_dst_set(skb, dst);
36feaac35   Hangbin Liu   ip6_tunnel: respe...
1205
1206
1207
1208
1209
1210
1211
1212
  	if (hop_limit == 0) {
  		if (skb->protocol == htons(ETH_P_IP))
  			hop_limit = ip_hdr(skb)->ttl;
  		else if (skb->protocol == htons(ETH_P_IPV6))
  			hop_limit = ipv6_hdr(skb)->hop_limit;
  		else
  			hop_limit = ip6_dst_hoplimit(dst);
  	}
3d483058c   Hannes Frederic Sowa   ipv6: wire up skb...
1213

058214a4d   Tom Herbert   ip6_tun: Add infr...
1214
1215
1216
  	/* Calculate max headroom for all the headers and adjust
  	 * needed_headroom if necessary.
  	 */
8eb30be03   Tom Herbert   ipv6: Create ip6_...
1217
  	max_headroom = LL_RESERVED_SPACE(dst->dev) + sizeof(struct ipv6hdr)
058214a4d   Tom Herbert   ip6_tun: Add infr...
1218
  			+ dst->header_len + t->hlen;
8eb30be03   Tom Herbert   ipv6: Create ip6_...
1219
1220
  	if (max_headroom > dev->needed_headroom)
  		dev->needed_headroom = max_headroom;
9e7c5b396   Alexander Ovechkin   ip6_tunnel: set i...
1221
  	skb_set_inner_ipproto(skb, proto);
058214a4d   Tom Herbert   ip6_tun: Add infr...
1222
1223
1224
  	err = ip6_tnl_encap(skb, t, &proto, fl6);
  	if (err)
  		return err;
d4d576f5a   Stefano Brivio   ip6_tunnel: Fix e...
1225
1226
1227
1228
  	if (encap_limit >= 0) {
  		init_tel_txopt(&opt, encap_limit);
  		ipv6_push_frag_opts(skb, &opt.ops, &proto);
  	}
e2d1bca7e   Arnaldo Carvalho de Melo   [SK_BUFF]: Use sk...
1229
1230
  	skb_push(skb, sizeof(struct ipv6hdr));
  	skb_reset_network_header(skb);
0660e03f6   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
1231
  	ipv6h = ipv6_hdr(skb);
0e9a70956   Peter Dawson   ip6_tunnel, ip6_g...
1232
  	ip6_flow_hdr(ipv6h, dsfield,
42240901f   Tom Herbert   ipv6: Implement d...
1233
  		     ip6_make_flowlabel(net, skb, fl6->flowlabel, true, fl6));
8d79266bc   Alexei Starovoitov   ip6_tunnel: add c...
1234
  	ipv6h->hop_limit = hop_limit;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1235
  	ipv6h->nexthdr = proto;
4e3fd7a06   Alexey Dobriyan   net: remove ipv6_...
1236
1237
  	ipv6h->saddr = fl6->saddr;
  	ipv6h->daddr = fl6->daddr;
79b16aade   David Miller   udp_tunnel: Pass ...
1238
  	ip6tunnel_xmit(NULL, skb, dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1239
1240
1241
1242
1243
  	return 0;
  tx_err_link_failure:
  	stats->tx_carrier_errors++;
  	dst_link_failure(skb);
  tx_err_dst_release:
cdf3464e6   Martin KaFai Lau   ipv6: Fix dst_ent...
1244
  	dst_release(dst);
61ec2aec2   Yasuyuki Kozakai   [IPV6] IP6TUNNEL:...
1245
1246
  	return err;
  }
8eb30be03   Tom Herbert   ipv6: Create ip6_...
1247
  EXPORT_SYMBOL(ip6_tnl_xmit);
61ec2aec2   Yasuyuki Kozakai   [IPV6] IP6TUNNEL:...
1248
1249
  
  static inline int
e7bb18e6c   Vadim Fedorenko   ip6_tunnel: simpl...
1250
1251
  ipxip6_tnl_xmit(struct sk_buff *skb, struct net_device *dev,
  		u8 protocol)
c4d3efafc   Yasuyuki Kozakai   [IPV6] IP6TUNNEL:...
1252
1253
  {
  	struct ip6_tnl *t = netdev_priv(dev);
e7bb18e6c   Vadim Fedorenko   ip6_tunnel: simpl...
1254
  	struct ipv6hdr *ipv6h;
76c0ddd8c   Paolo Abeni   ip6_tunnel: be ca...
1255
  	const struct iphdr  *iph;
c4d3efafc   Yasuyuki Kozakai   [IPV6] IP6TUNNEL:...
1256
  	int encap_limit = -1;
e7bb18e6c   Vadim Fedorenko   ip6_tunnel: simpl...
1257
  	__u16 offset;
4c9483b2f   David S. Miller   ipv6: Convert to ...
1258
  	struct flowi6 fl6;
e7bb18e6c   Vadim Fedorenko   ip6_tunnel: simpl...
1259
  	__u8 dsfield, orig_dsfield;
c4d3efafc   Yasuyuki Kozakai   [IPV6] IP6TUNNEL:...
1260
  	__u32 mtu;
acf722f73   Alexey Andriyanov   ip6_tunnel: allow...
1261
  	u8 tproto;
c4d3efafc   Yasuyuki Kozakai   [IPV6] IP6TUNNEL:...
1262
  	int err;
6aa7de059   Mark Rutland   locking/atomics: ...
1263
  	tproto = READ_ONCE(t->parms.proto);
e7bb18e6c   Vadim Fedorenko   ip6_tunnel: simpl...
1264
  	if (tproto != protocol && tproto != 0)
c4d3efafc   Yasuyuki Kozakai   [IPV6] IP6TUNNEL:...
1265
  		return -1;
8d79266bc   Alexei Starovoitov   ip6_tunnel: add c...
1266
1267
1268
  	if (t->parms.collect_md) {
  		struct ip_tunnel_info *tun_info;
  		const struct ip_tunnel_key *key;
c4d3efafc   Yasuyuki Kozakai   [IPV6] IP6TUNNEL:...
1269

8d79266bc   Alexei Starovoitov   ip6_tunnel: add c...
1270
1271
1272
1273
1274
1275
  		tun_info = skb_tunnel_info(skb);
  		if (unlikely(!tun_info || !(tun_info->mode & IP_TUNNEL_INFO_TX) ||
  			     ip_tunnel_info_af(tun_info) != AF_INET6))
  			return -1;
  		key = &tun_info->key;
  		memset(&fl6, 0, sizeof(fl6));
e7bb18e6c   Vadim Fedorenko   ip6_tunnel: simpl...
1276
  		fl6.flowi6_proto = protocol;
3789cabaa   Shmulik Ladkani   ip6_tunnel: colle...
1277
  		fl6.saddr = key->u.ipv6.src;
8d79266bc   Alexei Starovoitov   ip6_tunnel: add c...
1278
1279
  		fl6.daddr = key->u.ipv6.dst;
  		fl6.flowlabel = key->label;
46f8cd9d2   Haishuang Yan   ip6_tunnel: Corre...
1280
  		dsfield =  key->tos;
e7bb18e6c   Vadim Fedorenko   ip6_tunnel: simpl...
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
  		switch (protocol) {
  		case IPPROTO_IPIP:
  			iph = ip_hdr(skb);
  			orig_dsfield = ipv4_get_dsfield(iph);
  			break;
  		case IPPROTO_IPV6:
  			ipv6h = ipv6_hdr(skb);
  			orig_dsfield = ipv6_get_dsfield(ipv6h);
  			break;
  		default:
  			orig_dsfield = dsfield;
  			break;
  		}
8d79266bc   Alexei Starovoitov   ip6_tunnel: add c...
1294
1295
1296
  	} else {
  		if (!(t->parms.flags & IP6_TNL_F_IGN_ENCAP_LIMIT))
  			encap_limit = t->parms.encap_limit;
e7bb18e6c   Vadim Fedorenko   ip6_tunnel: simpl...
1297
1298
1299
1300
1301
1302
1303
1304
  		if (protocol == IPPROTO_IPV6) {
  			offset = ip6_tnl_parse_tlv_enc_lim(skb,
  						skb_network_header(skb));
  			/* ip6_tnl_parse_tlv_enc_lim() might have
  			 * reallocated skb->head
  			 */
  			if (offset > 0) {
  				struct ipv6_tlv_tnl_enc_lim *tel;
c4d3efafc   Yasuyuki Kozakai   [IPV6] IP6TUNNEL:...
1305

e7bb18e6c   Vadim Fedorenko   ip6_tunnel: simpl...
1306
1307
1308
1309
1310
1311
1312
  				tel = (void *)&skb_network_header(skb)[offset];
  				if (tel->encap_limit == 0) {
  					icmpv6_send(skb, ICMPV6_PARAMPROB,
  						ICMPV6_HDR_FIELD, offset + 2);
  					return -1;
  				}
  				encap_limit = tel->encap_limit - 1;
8d79266bc   Alexei Starovoitov   ip6_tunnel: add c...
1313
  			}
61ec2aec2   Yasuyuki Kozakai   [IPV6] IP6TUNNEL:...
1314
  		}
61ec2aec2   Yasuyuki Kozakai   [IPV6] IP6TUNNEL:...
1315

8d79266bc   Alexei Starovoitov   ip6_tunnel: add c...
1316
  		memcpy(&fl6, &t->fl.u.ip6, sizeof(fl6));
e7bb18e6c   Vadim Fedorenko   ip6_tunnel: simpl...
1317
  		fl6.flowi6_proto = protocol;
61ec2aec2   Yasuyuki Kozakai   [IPV6] IP6TUNNEL:...
1318

8d79266bc   Alexei Starovoitov   ip6_tunnel: add c...
1319
1320
  		if (t->parms.flags & IP6_TNL_F_USE_ORIG_FWMARK)
  			fl6.flowi6_mark = skb->mark;
0a473b82c   Craig Gallek   ip6_tunnel: Allow...
1321
1322
  		else
  			fl6.flowi6_mark = t->parms.fwmark;
e7bb18e6c   Vadim Fedorenko   ip6_tunnel: simpl...
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
  		switch (protocol) {
  		case IPPROTO_IPIP:
  			iph = ip_hdr(skb);
  			orig_dsfield = ipv4_get_dsfield(iph);
  			if (t->parms.flags & IP6_TNL_F_USE_ORIG_TCLASS)
  				dsfield = orig_dsfield;
  			else
  				dsfield = ip6_tclass(t->parms.flowinfo);
  			break;
  		case IPPROTO_IPV6:
  			ipv6h = ipv6_hdr(skb);
  			orig_dsfield = ipv6_get_dsfield(ipv6h);
  			if (t->parms.flags & IP6_TNL_F_USE_ORIG_TCLASS)
  				dsfield = orig_dsfield;
  			else
  				dsfield = ip6_tclass(t->parms.flowinfo);
  			if (t->parms.flags & IP6_TNL_F_USE_ORIG_FLOWLABEL)
  				fl6.flowlabel |= ip6_flowlabel(ipv6h);
  			break;
  		default:
6c11fbf97   Vadim Fedorenko   ip6_tunnel: add M...
1343
  			orig_dsfield = dsfield = ip6_tclass(t->parms.flowinfo);
e7bb18e6c   Vadim Fedorenko   ip6_tunnel: simpl...
1344
1345
  			break;
  		}
8d79266bc   Alexei Starovoitov   ip6_tunnel: add c...
1346
  	}
61ec2aec2   Yasuyuki Kozakai   [IPV6] IP6TUNNEL:...
1347

e2d118a1c   Lorenzo Colitti   net: inet: Suppor...
1348
  	fl6.flowi6_uid = sock_net_uid(dev_net(dev), NULL);
e7bb18e6c   Vadim Fedorenko   ip6_tunnel: simpl...
1349
  	dsfield = INET_ECN_encapsulate(dsfield, orig_dsfield);
e2d118a1c   Lorenzo Colitti   net: inet: Suppor...
1350

815d22e55   Tom Herbert   ip6ip6: Support f...
1351
1352
  	if (iptunnel_handle_offloads(skb, SKB_GSO_IPXIP6))
  		return -1;
8eb30be03   Tom Herbert   ipv6: Create ip6_...
1353
  	err = ip6_tnl_xmit(skb, dev, dsfield, &fl6, encap_limit, &mtu,
e7bb18e6c   Vadim Fedorenko   ip6_tunnel: simpl...
1354
  			   protocol);
61ec2aec2   Yasuyuki Kozakai   [IPV6] IP6TUNNEL:...
1355
  	if (err != 0) {
e7bb18e6c   Vadim Fedorenko   ip6_tunnel: simpl...
1356
  		/* XXX: send ICMP error even if DF is not set. */
61ec2aec2   Yasuyuki Kozakai   [IPV6] IP6TUNNEL:...
1357
  		if (err == -EMSGSIZE)
e7bb18e6c   Vadim Fedorenko   ip6_tunnel: simpl...
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
  			switch (protocol) {
  			case IPPROTO_IPIP:
  				icmp_send(skb, ICMP_DEST_UNREACH,
  					  ICMP_FRAG_NEEDED, htonl(mtu));
  				break;
  			case IPPROTO_IPV6:
  				icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu);
  				break;
  			default:
  				break;
  			}
61ec2aec2   Yasuyuki Kozakai   [IPV6] IP6TUNNEL:...
1369
1370
1371
1372
1373
  		return -1;
  	}
  
  	return 0;
  }
6fef4c0c8   Stephen Hemminger   netdev: convert p...
1374
  static netdev_tx_t
8eb30be03   Tom Herbert   ipv6: Create ip6_...
1375
  ip6_tnl_start_xmit(struct sk_buff *skb, struct net_device *dev)
61ec2aec2   Yasuyuki Kozakai   [IPV6] IP6TUNNEL:...
1376
1377
  {
  	struct ip6_tnl *t = netdev_priv(dev);
3dca02af3   Pavel Emelyanov   ip6tnl: Use on-de...
1378
  	struct net_device_stats *stats = &t->dev->stats;
e7bb18e6c   Vadim Fedorenko   ip6_tunnel: simpl...
1379
  	u8 ipproto;
61ec2aec2   Yasuyuki Kozakai   [IPV6] IP6TUNNEL:...
1380
  	int ret;
cb9f1b783   Willem de Bruijn   ip: validate head...
1381
1382
  	if (!pskb_inet_may_pull(skb))
  		goto tx_err;
61ec2aec2   Yasuyuki Kozakai   [IPV6] IP6TUNNEL:...
1383
  	switch (skb->protocol) {
606780404   Arnaldo Carvalho de Melo   net: Use hton[sl]...
1384
  	case htons(ETH_P_IP):
e7bb18e6c   Vadim Fedorenko   ip6_tunnel: simpl...
1385
  		ipproto = IPPROTO_IPIP;
c4d3efafc   Yasuyuki Kozakai   [IPV6] IP6TUNNEL:...
1386
  		break;
606780404   Arnaldo Carvalho de Melo   net: Use hton[sl]...
1387
  	case htons(ETH_P_IPV6):
e7bb18e6c   Vadim Fedorenko   ip6_tunnel: simpl...
1388
1389
1390
  		if (ip6_tnl_addr_conflict(t, ipv6_hdr(skb)))
  			goto tx_err;
  		ipproto = IPPROTO_IPV6;
61ec2aec2   Yasuyuki Kozakai   [IPV6] IP6TUNNEL:...
1391
  		break;
6c11fbf97   Vadim Fedorenko   ip6_tunnel: add M...
1392
1393
1394
  	case htons(ETH_P_MPLS_UC):
  		ipproto = IPPROTO_MPLS;
  		break;
61ec2aec2   Yasuyuki Kozakai   [IPV6] IP6TUNNEL:...
1395
1396
1397
  	default:
  		goto tx_err;
  	}
e7bb18e6c   Vadim Fedorenko   ip6_tunnel: simpl...
1398
  	ret = ipxip6_tnl_xmit(skb, dev, ipproto);
61ec2aec2   Yasuyuki Kozakai   [IPV6] IP6TUNNEL:...
1399
1400
  	if (ret < 0)
  		goto tx_err;
6ed106549   Patrick McHardy   net: use NETDEV_T...
1401
  	return NETDEV_TX_OK;
61ec2aec2   Yasuyuki Kozakai   [IPV6] IP6TUNNEL:...
1402

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1403
1404
1405
1406
  tx_err:
  	stats->tx_errors++;
  	stats->tx_dropped++;
  	kfree_skb(skb);
6ed106549   Patrick McHardy   net: use NETDEV_T...
1407
  	return NETDEV_TX_OK;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1408
  }
3144581cb   Yasuyuki Kozakai   [IPV6] IP6TUNNEL:...
1409
  static void ip6_tnl_link_config(struct ip6_tnl *t)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1410
1411
  {
  	struct net_device *dev = t->dev;
5fdcce211   William Dauchy   net, ip6_tunnel: ...
1412
  	struct net_device *tdev = NULL;
c12b395a4   xeb@mail.ru   gre: Support GRE ...
1413
  	struct __ip6_tnl_parm *p = &t->parms;
4c9483b2f   David S. Miller   ipv6: Convert to ...
1414
  	struct flowi6 *fl6 = &t->fl.u.ip6;
5fdcce211   William Dauchy   net, ip6_tunnel: ...
1415
  	unsigned int mtu;
058214a4d   Tom Herbert   ip6_tun: Add infr...
1416
  	int t_hlen;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1417

3a6d54c56   Jiri Pirko   net: remove needl...
1418
1419
  	memcpy(dev->dev_addr, &p->laddr, sizeof(struct in6_addr));
  	memcpy(dev->broadcast, &p->raddr, sizeof(struct in6_addr));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1420
1421
  
  	/* Set up flowi template */
4e3fd7a06   Alexey Dobriyan   net: remove ipv6_...
1422
1423
  	fl6->saddr = p->laddr;
  	fl6->daddr = p->raddr;
4c9483b2f   David S. Miller   ipv6: Convert to ...
1424
1425
  	fl6->flowi6_oif = p->link;
  	fl6->flowlabel = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1426
1427
  
  	if (!(p->flags&IP6_TNL_F_USE_ORIG_TCLASS))
4c9483b2f   David S. Miller   ipv6: Convert to ...
1428
  		fl6->flowlabel |= IPV6_TCLASS_MASK & p->flowinfo;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1429
  	if (!(p->flags&IP6_TNL_F_USE_ORIG_FLOWLABEL))
4c9483b2f   David S. Miller   ipv6: Convert to ...
1430
  		fl6->flowlabel |= IPV6_FLOWLABEL_MASK & p->flowinfo;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1431

d0087b29f   Ville Nuorvala   ipv6_tunnel: Allo...
1432
1433
  	p->flags &= ~(IP6_TNL_F_CAP_XMIT|IP6_TNL_F_CAP_RCV|IP6_TNL_F_CAP_PER_PACKET);
  	p->flags |= ip6_tnl_get_cap(t, &p->laddr, &p->raddr);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1434
1435
1436
1437
1438
  
  	if (p->flags&IP6_TNL_F_CAP_XMIT && p->flags&IP6_TNL_F_CAP_RCV)
  		dev->flags |= IFF_POINTOPOINT;
  	else
  		dev->flags &= ~IFF_POINTOPOINT;
058214a4d   Tom Herbert   ip6_tun: Add infr...
1439
1440
1441
  	t->tun_hlen = 0;
  	t->hlen = t->encap_hlen + t->tun_hlen;
  	t_hlen = t->hlen + sizeof(struct ipv6hdr);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1442
  	if (p->flags & IP6_TNL_F_CAP_XMIT) {
305d4b3ce   Ville Nuorvala   [IPV6]: Allow lin...
1443
1444
  		int strict = (ipv6_addr_type(&p->raddr) &
  			      (IPV6_ADDR_MULTICAST|IPV6_ADDR_LINKLOCAL));
0bd876282   Nicolas Dichtel   ip6tnl: add x-net...
1445
  		struct rt6_info *rt = rt6_lookup(t->net,
2f7f54b72   Pavel Emelyanov   [IP6TUNNEL]: Use ...
1446
  						 &p->raddr, &p->laddr,
b75cc8f90   David Ahern   net/ipv6: Pass sk...
1447
  						 p->link, NULL, strict);
5fdcce211   William Dauchy   net, ip6_tunnel: ...
1448
1449
1450
1451
  		if (rt) {
  			tdev = rt->dst.dev;
  			ip6_rt_put(rt);
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1452

5fdcce211   William Dauchy   net, ip6_tunnel: ...
1453
1454
  		if (!tdev && p->link)
  			tdev = __dev_get_by_index(t->net, p->link);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1455

5fdcce211   William Dauchy   net, ip6_tunnel: ...
1456
1457
1458
  		if (tdev) {
  			dev->hard_header_len = tdev->hard_header_len + t_hlen;
  			mtu = min_t(unsigned int, tdev->mtu, IP6_MAX_MTU);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1459

5fdcce211   William Dauchy   net, ip6_tunnel: ...
1460
  			dev->mtu = mtu - t_hlen;
381601e5b   Anders Franzen   Make the ip6_tunn...
1461
  			if (!(t->parms.flags & IP6_TNL_F_IGN_ENCAP_LIMIT))
67ba4152e   Ian Morris   ipv6: White-space...
1462
  				dev->mtu -= 8;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1463
1464
1465
1466
  
  			if (dev->mtu < IPV6_MIN_MTU)
  				dev->mtu = IPV6_MIN_MTU;
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1467
1468
1469
1470
  	}
  }
  
  /**
3144581cb   Yasuyuki Kozakai   [IPV6] IP6TUNNEL:...
1471
   * ip6_tnl_change - update the tunnel parameters
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1472
1473
   *   @t: tunnel to be changed
   *   @p: tunnel configuration parameters
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1474
1475
   *
   * Description:
3144581cb   Yasuyuki Kozakai   [IPV6] IP6TUNNEL:...
1476
   *   ip6_tnl_change() updates the tunnel parameters
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1477
1478
1479
   **/
  
  static int
c12b395a4   xeb@mail.ru   gre: Support GRE ...
1480
  ip6_tnl_change(struct ip6_tnl *t, const struct __ip6_tnl_parm *p)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1481
  {
4e3fd7a06   Alexey Dobriyan   net: remove ipv6_...
1482
1483
  	t->parms.laddr = p->laddr;
  	t->parms.raddr = p->raddr;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1484
1485
1486
1487
  	t->parms.flags = p->flags;
  	t->parms.hop_limit = p->hop_limit;
  	t->parms.encap_limit = p->encap_limit;
  	t->parms.flowinfo = p->flowinfo;
8181b8c1f   Gabor Fekete   [IPV6]: Update pa...
1488
  	t->parms.link = p->link;
502b09356   Yasuyuki Kozakai   [IPV6] IP6TUNNEL:...
1489
  	t->parms.proto = p->proto;
0a473b82c   Craig Gallek   ip6_tunnel: Allow...
1490
  	t->parms.fwmark = p->fwmark;
607f725f6   Paolo Abeni   net: replace dst_...
1491
  	dst_cache_reset(&t->dst_cache);
3144581cb   Yasuyuki Kozakai   [IPV6] IP6TUNNEL:...
1492
  	ip6_tnl_link_config(t);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1493
1494
  	return 0;
  }
0b1124572   Nicolas Dichtel   ip6tnl: add suppo...
1495
1496
  static int ip6_tnl_update(struct ip6_tnl *t, struct __ip6_tnl_parm *p)
  {
0bd876282   Nicolas Dichtel   ip6tnl: add x-net...
1497
  	struct net *net = t->net;
0b1124572   Nicolas Dichtel   ip6tnl: add suppo...
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
  	struct ip6_tnl_net *ip6n = net_generic(net, ip6_tnl_net_id);
  	int err;
  
  	ip6_tnl_unlink(ip6n, t);
  	synchronize_net();
  	err = ip6_tnl_change(t, p);
  	ip6_tnl_link(ip6n, t);
  	netdev_state_change(t->dev);
  	return err;
  }
acf722f73   Alexey Andriyanov   ip6_tunnel: allow...
1508
1509
1510
1511
1512
1513
1514
  static int ip6_tnl0_update(struct ip6_tnl *t, struct __ip6_tnl_parm *p)
  {
  	/* for default tnl0 device allow to change only the proto */
  	t->parms.proto = p->proto;
  	netdev_state_change(t->dev);
  	return 0;
  }
c12b395a4   xeb@mail.ru   gre: Support GRE ...
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
  static void
  ip6_tnl_parm_from_user(struct __ip6_tnl_parm *p, const struct ip6_tnl_parm *u)
  {
  	p->laddr = u->laddr;
  	p->raddr = u->raddr;
  	p->flags = u->flags;
  	p->hop_limit = u->hop_limit;
  	p->encap_limit = u->encap_limit;
  	p->flowinfo = u->flowinfo;
  	p->link = u->link;
  	p->proto = u->proto;
  	memcpy(p->name, u->name, sizeof(u->name));
  }
  
  static void
  ip6_tnl_parm_to_user(struct ip6_tnl_parm *u, const struct __ip6_tnl_parm *p)
  {
  	u->laddr = p->laddr;
  	u->raddr = p->raddr;
  	u->flags = p->flags;
  	u->hop_limit = p->hop_limit;
  	u->encap_limit = p->encap_limit;
  	u->flowinfo = p->flowinfo;
  	u->link = p->link;
  	u->proto = p->proto;
  	memcpy(u->name, p->name, sizeof(u->name));
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1542
  /**
3144581cb   Yasuyuki Kozakai   [IPV6] IP6TUNNEL:...
1543
   * ip6_tnl_ioctl - configure ipv6 tunnels from userspace
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1544
1545
1546
1547
1548
   *   @dev: virtual device associated with tunnel
   *   @ifr: parameters passed from userspace
   *   @cmd: command to be performed
   *
   * Description:
3144581cb   Yasuyuki Kozakai   [IPV6] IP6TUNNEL:...
1549
   *   ip6_tnl_ioctl() is used for managing IPv6 tunnels
1ab1457c4   YOSHIFUJI Hideaki   [NET] IPV6: Fix w...
1550
   *   from userspace.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1551
1552
1553
1554
1555
1556
1557
   *
   *   The possible commands are the following:
   *     %SIOCGETTUNNEL: get tunnel parameters for device
   *     %SIOCADDTUNNEL: add tunnel matching given tunnel parameters
   *     %SIOCCHGTUNNEL: change tunnel parameters to those given
   *     %SIOCDELTUNNEL: delete tunnel
   *
1ab1457c4   YOSHIFUJI Hideaki   [NET] IPV6: Fix w...
1558
   *   The fallback device "ip6tnl0", created during module
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
   *   initialization, can be used for creating other tunnel devices.
   *
   * Return:
   *   0 on success,
   *   %-EFAULT if unable to copy data to or from userspace,
   *   %-EPERM if current process hasn't %CAP_NET_ADMIN set
   *   %-EINVAL if passed tunnel parameters are invalid,
   *   %-EEXIST if changing a tunnel's parameters would cause a conflict
   *   %-ENODEV if attempting to change or delete a nonexisting device
   **/
  
  static int
3144581cb   Yasuyuki Kozakai   [IPV6] IP6TUNNEL:...
1571
  ip6_tnl_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1572
1573
  {
  	int err = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1574
  	struct ip6_tnl_parm p;
c12b395a4   xeb@mail.ru   gre: Support GRE ...
1575
  	struct __ip6_tnl_parm p1;
74462f0d4   Nicolas Dichtel   ip6_tunnel: use t...
1576
1577
  	struct ip6_tnl *t = netdev_priv(dev);
  	struct net *net = t->net;
2dd02c897   Pavel Emelyanov   [IP6TUNNEL]: Add ...
1578
  	struct ip6_tnl_net *ip6n = net_generic(net, ip6_tnl_net_id);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1579

0d3c703a9   Tom Herbert   ipv6: Cleanup IPv...
1580
  	memset(&p1, 0, sizeof(p1));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1581
1582
  	switch (cmd) {
  	case SIOCGETTUNNEL:
15820e129   Pavel Emelyanov   [IP6TUNNEL]: Make...
1583
  		if (dev == ip6n->fb_tnl_dev) {
67ba4152e   Ian Morris   ipv6: White-space...
1584
  			if (copy_from_user(&p, ifr->ifr_ifru.ifru_data, sizeof(p))) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1585
1586
1587
  				err = -EFAULT;
  				break;
  			}
c12b395a4   xeb@mail.ru   gre: Support GRE ...
1588
1589
  			ip6_tnl_parm_from_user(&p1, &p);
  			t = ip6_tnl_locate(net, &p1, 0);
37355565b   Nicolas Dichtel   ip6_tunnel: fix e...
1590
  			if (IS_ERR(t))
74462f0d4   Nicolas Dichtel   ip6_tunnel: use t...
1591
  				t = netdev_priv(dev);
5ef5d6c56   Dan Carpenter   gre: information ...
1592
1593
  		} else {
  			memset(&p, 0, sizeof(p));
567131a72   Ville Nuorvala   [IPV6]: Fix SIOCC...
1594
  		}
c12b395a4   xeb@mail.ru   gre: Support GRE ...
1595
  		ip6_tnl_parm_to_user(&p, &t->parms);
67ba4152e   Ian Morris   ipv6: White-space...
1596
  		if (copy_to_user(ifr->ifr_ifru.ifru_data, &p, sizeof(p))) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1597
1598
1599
1600
1601
1602
  			err = -EFAULT;
  		}
  		break;
  	case SIOCADDTUNNEL:
  	case SIOCCHGTUNNEL:
  		err = -EPERM;
af31f412c   Eric W. Biederman   net: Allow userns...
1603
  		if (!ns_capable(net->user_ns, CAP_NET_ADMIN))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1604
  			break;
567131a72   Ville Nuorvala   [IPV6]: Fix SIOCC...
1605
  		err = -EFAULT;
67ba4152e   Ian Morris   ipv6: White-space...
1606
  		if (copy_from_user(&p, ifr->ifr_ifru.ifru_data, sizeof(p)))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1607
  			break;
567131a72   Ville Nuorvala   [IPV6]: Fix SIOCC...
1608
  		err = -EINVAL;
502b09356   Yasuyuki Kozakai   [IPV6] IP6TUNNEL:...
1609
1610
  		if (p.proto != IPPROTO_IPV6 && p.proto != IPPROTO_IPIP &&
  		    p.proto != 0)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1611
  			break;
c12b395a4   xeb@mail.ru   gre: Support GRE ...
1612
1613
  		ip6_tnl_parm_from_user(&p1, &p);
  		t = ip6_tnl_locate(net, &p1, cmd == SIOCADDTUNNEL);
acf722f73   Alexey Andriyanov   ip6_tunnel: allow...
1614
  		if (cmd == SIOCCHGTUNNEL) {
37355565b   Nicolas Dichtel   ip6_tunnel: fix e...
1615
  			if (!IS_ERR(t)) {
567131a72   Ville Nuorvala   [IPV6]: Fix SIOCC...
1616
1617
1618
1619
1620
1621
  				if (t->dev != dev) {
  					err = -EEXIST;
  					break;
  				}
  			} else
  				t = netdev_priv(dev);
acf722f73   Alexey Andriyanov   ip6_tunnel: allow...
1622
1623
1624
1625
  			if (dev == ip6n->fb_tnl_dev)
  				err = ip6_tnl0_update(t, &p1);
  			else
  				err = ip6_tnl_update(t, &p1);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1626
  		}
37355565b   Nicolas Dichtel   ip6_tunnel: fix e...
1627
  		if (!IS_ERR(t)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1628
  			err = 0;
c12b395a4   xeb@mail.ru   gre: Support GRE ...
1629
1630
  			ip6_tnl_parm_to_user(&p, &t->parms);
  			if (copy_to_user(ifr->ifr_ifru.ifru_data, &p, sizeof(p)))
567131a72   Ville Nuorvala   [IPV6]: Fix SIOCC...
1631
  				err = -EFAULT;
37355565b   Nicolas Dichtel   ip6_tunnel: fix e...
1632
1633
1634
  		} else {
  			err = PTR_ERR(t);
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1635
1636
1637
  		break;
  	case SIOCDELTUNNEL:
  		err = -EPERM;
af31f412c   Eric W. Biederman   net: Allow userns...
1638
  		if (!ns_capable(net->user_ns, CAP_NET_ADMIN))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1639
  			break;
15820e129   Pavel Emelyanov   [IP6TUNNEL]: Make...
1640
  		if (dev == ip6n->fb_tnl_dev) {
567131a72   Ville Nuorvala   [IPV6]: Fix SIOCC...
1641
  			err = -EFAULT;
67ba4152e   Ian Morris   ipv6: White-space...
1642
  			if (copy_from_user(&p, ifr->ifr_ifru.ifru_data, sizeof(p)))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1643
  				break;
567131a72   Ville Nuorvala   [IPV6]: Fix SIOCC...
1644
  			err = -ENOENT;
c12b395a4   xeb@mail.ru   gre: Support GRE ...
1645
1646
  			ip6_tnl_parm_from_user(&p1, &p);
  			t = ip6_tnl_locate(net, &p1, 0);
37355565b   Nicolas Dichtel   ip6_tunnel: fix e...
1647
  			if (IS_ERR(t))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1648
  				break;
567131a72   Ville Nuorvala   [IPV6]: Fix SIOCC...
1649
  			err = -EPERM;
15820e129   Pavel Emelyanov   [IP6TUNNEL]: Make...
1650
  			if (t->dev == ip6n->fb_tnl_dev)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1651
  				break;
567131a72   Ville Nuorvala   [IPV6]: Fix SIOCC...
1652
  			dev = t->dev;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1653
  		}
22f8cde5b   Stephen Hemminger   [NET]: unregister...
1654
1655
  		err = 0;
  		unregister_netdevice(dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1656
1657
1658
1659
1660
1661
1662
1663
  		break;
  	default:
  		err = -EINVAL;
  	}
  	return err;
  }
  
  /**
3144581cb   Yasuyuki Kozakai   [IPV6] IP6TUNNEL:...
1664
   * ip6_tnl_change_mtu - change mtu manually for tunnel device
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1665
1666
1667
1668
1669
1670
1671
   *   @dev: virtual device associated with tunnel
   *   @new_mtu: the new mtu
   *
   * Return:
   *   0 on success,
   *   %-EINVAL if mtu too small
   **/
79ecb90e6   Tom Herbert   ipv6: Generic tun...
1672
  int ip6_tnl_change_mtu(struct net_device *dev, int new_mtu)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1673
  {
582442d6d   Oussama Ghorbel   ipv6: Allow the M...
1674
  	struct ip6_tnl *tnl = netdev_priv(dev);
2fa771be9   Xin Long   ip6_tunnel: allow...
1675
1676
  	if (tnl->parms.proto == IPPROTO_IPV6) {
  		if (new_mtu < IPV6_MIN_MTU)
582442d6d   Oussama Ghorbel   ipv6: Allow the M...
1677
1678
  			return -EINVAL;
  	} else {
2fa771be9   Xin Long   ip6_tunnel: allow...
1679
  		if (new_mtu < ETH_MIN_MTU)
582442d6d   Oussama Ghorbel   ipv6: Allow the M...
1680
  			return -EINVAL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1681
  	}
f7ff1fde9   Nicolas Dichtel   ip6_tunnel: remov...
1682
1683
1684
1685
1686
1687
1688
  	if (tnl->parms.proto == IPPROTO_IPV6 || tnl->parms.proto == 0) {
  		if (new_mtu > IP6_MAX_MTU - dev->hard_header_len)
  			return -EINVAL;
  	} else {
  		if (new_mtu > IP_MAX_MTU - dev->hard_header_len)
  			return -EINVAL;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1689
1690
1691
  	dev->mtu = new_mtu;
  	return 0;
  }
79ecb90e6   Tom Herbert   ipv6: Generic tun...
1692
  EXPORT_SYMBOL(ip6_tnl_change_mtu);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1693

ecf2c06a8   Nicolas Dichtel   ip6tnl,gre6,vti6:...
1694
1695
1696
1697
1698
1699
1700
  int ip6_tnl_get_iflink(const struct net_device *dev)
  {
  	struct ip6_tnl *t = netdev_priv(dev);
  
  	return t->parms.link;
  }
  EXPORT_SYMBOL(ip6_tnl_get_iflink);
1326c3d5a   Stephen Hemminger   ipv6: convert tun...
1701

058214a4d   Tom Herbert   ip6_tun: Add infr...
1702
1703
1704
1705
1706
1707
1708
1709
1710
1711
1712
1713
1714
1715
1716
1717
1718
1719
1720
1721
1722
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734
1735
1736
1737
1738
1739
1740
1741
1742
1743
1744
1745
1746
1747
1748
1749
1750
1751
1752
1753
  int ip6_tnl_encap_add_ops(const struct ip6_tnl_encap_ops *ops,
  			  unsigned int num)
  {
  	if (num >= MAX_IPTUN_ENCAP_OPS)
  		return -ERANGE;
  
  	return !cmpxchg((const struct ip6_tnl_encap_ops **)
  			&ip6tun_encaps[num],
  			NULL, ops) ? 0 : -1;
  }
  EXPORT_SYMBOL(ip6_tnl_encap_add_ops);
  
  int ip6_tnl_encap_del_ops(const struct ip6_tnl_encap_ops *ops,
  			  unsigned int num)
  {
  	int ret;
  
  	if (num >= MAX_IPTUN_ENCAP_OPS)
  		return -ERANGE;
  
  	ret = (cmpxchg((const struct ip6_tnl_encap_ops **)
  		       &ip6tun_encaps[num],
  		       ops, NULL) == ops) ? 0 : -1;
  
  	synchronize_net();
  
  	return ret;
  }
  EXPORT_SYMBOL(ip6_tnl_encap_del_ops);
  
  int ip6_tnl_encap_setup(struct ip6_tnl *t,
  			struct ip_tunnel_encap *ipencap)
  {
  	int hlen;
  
  	memset(&t->encap, 0, sizeof(t->encap));
  
  	hlen = ip6_encap_hlen(ipencap);
  	if (hlen < 0)
  		return hlen;
  
  	t->encap.type = ipencap->type;
  	t->encap.sport = ipencap->sport;
  	t->encap.dport = ipencap->dport;
  	t->encap.flags = ipencap->flags;
  
  	t->encap_hlen = hlen;
  	t->hlen = t->encap_hlen + t->tun_hlen;
  
  	return 0;
  }
  EXPORT_SYMBOL_GPL(ip6_tnl_encap_setup);
1326c3d5a   Stephen Hemminger   ipv6: convert tun...
1754
  static const struct net_device_ops ip6_tnl_netdev_ops = {
6c6151daa   Steffen Klassert   ip6_tunnel: Use i...
1755
  	.ndo_init	= ip6_tnl_dev_init,
8560f2266   Eric Dumazet   ip6tnl: percpu st...
1756
  	.ndo_uninit	= ip6_tnl_dev_uninit,
8eb30be03   Tom Herbert   ipv6: Create ip6_...
1757
  	.ndo_start_xmit = ip6_tnl_start_xmit,
8560f2266   Eric Dumazet   ip6tnl: percpu st...
1758
  	.ndo_do_ioctl	= ip6_tnl_ioctl,
1326c3d5a   Stephen Hemminger   ipv6: convert tun...
1759
  	.ndo_change_mtu = ip6_tnl_change_mtu,
8560f2266   Eric Dumazet   ip6tnl: percpu st...
1760
  	.ndo_get_stats	= ip6_get_stats,
ecf2c06a8   Nicolas Dichtel   ip6tnl,gre6,vti6:...
1761
  	.ndo_get_iflink = ip6_tnl_get_iflink,
1326c3d5a   Stephen Hemminger   ipv6: convert tun...
1762
  };
51c052d4f   Tom Herbert   ipv6: Set feature...
1763
1764
1765
1766
1767
  #define IPXIPX_FEATURES (NETIF_F_SG |		\
  			 NETIF_F_FRAGLIST |	\
  			 NETIF_F_HIGHDMA |	\
  			 NETIF_F_GSO_SOFTWARE |	\
  			 NETIF_F_HW_CSUM)
8560f2266   Eric Dumazet   ip6tnl: percpu st...
1768

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1769
  /**
3144581cb   Yasuyuki Kozakai   [IPV6] IP6TUNNEL:...
1770
   * ip6_tnl_dev_setup - setup virtual tunnel device
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1771
1772
1773
1774
1775
   *   @dev: virtual device associated with tunnel
   *
   * Description:
   *   Initialize function pointers and device parameters
   **/
3144581cb   Yasuyuki Kozakai   [IPV6] IP6TUNNEL:...
1776
  static void ip6_tnl_dev_setup(struct net_device *dev)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1777
  {
1326c3d5a   Stephen Hemminger   ipv6: convert tun...
1778
  	dev->netdev_ops = &ip6_tnl_netdev_ops;
e53ac9322   Jason A. Donenfeld   net: ipip: implem...
1779
  	dev->header_ops = &ip_tunnel_header_ops;
cf124db56   David S. Miller   net: Fix inconsis...
1780
1781
  	dev->needs_free_netdev = true;
  	dev->priv_destructor = ip6_dev_free;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1782
1783
  
  	dev->type = ARPHRD_TUNNEL6;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1784
1785
  	dev->flags |= IFF_NOARP;
  	dev->addr_len = sizeof(struct in6_addr);
058214a4d   Tom Herbert   ip6_tun: Add infr...
1786
  	dev->features |= NETIF_F_LLTX;
028758788   Eric Dumazet   net: better IFF_X...
1787
  	netif_keep_dst(dev);
51c052d4f   Tom Herbert   ipv6: Set feature...
1788
1789
1790
  
  	dev->features		|= IPXIPX_FEATURES;
  	dev->hw_features	|= IPXIPX_FEATURES;
e837735ec   Nicolas Dichtel   ip6_tunnel: ensur...
1791
1792
1793
  	/* This perm addr will be used as interface identifier by IPv6 */
  	dev->addr_assign_type = NET_ADDR_RANDOM;
  	eth_random_addr(dev->perm_addr);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1794
1795
1796
1797
  }
  
  
  /**
3144581cb   Yasuyuki Kozakai   [IPV6] IP6TUNNEL:...
1798
   * ip6_tnl_dev_init_gen - general initializer for all tunnel devices
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1799
1800
   *   @dev: virtual device associated with tunnel
   **/
8560f2266   Eric Dumazet   ip6tnl: percpu st...
1801
  static inline int
3144581cb   Yasuyuki Kozakai   [IPV6] IP6TUNNEL:...
1802
  ip6_tnl_dev_init_gen(struct net_device *dev)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1803
  {
2941a4863   Patrick McHardy   [NET]: Convert ne...
1804
  	struct ip6_tnl *t = netdev_priv(dev);
cdf3464e6   Martin KaFai Lau   ipv6: Fix dst_ent...
1805
  	int ret;
058214a4d   Tom Herbert   ip6_tun: Add infr...
1806
  	int t_hlen;
8560f2266   Eric Dumazet   ip6tnl: percpu st...
1807

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1808
  	t->dev = dev;
0bd876282   Nicolas Dichtel   ip6tnl: add x-net...
1809
  	t->net = dev_net(dev);
1c213bd24   WANG Cong   net: introduce ne...
1810
  	dev->tstats = netdev_alloc_pcpu_stats(struct pcpu_sw_netstats);
8560f2266   Eric Dumazet   ip6tnl: percpu st...
1811
1812
  	if (!dev->tstats)
  		return -ENOMEM;
cdf3464e6   Martin KaFai Lau   ipv6: Fix dst_ent...
1813

607f725f6   Paolo Abeni   net: replace dst_...
1814
  	ret = dst_cache_init(&t->dst_cache, GFP_KERNEL);
0d3c703a9   Tom Herbert   ipv6: Cleanup IPv...
1815
1816
1817
1818
1819
1820
  	if (ret)
  		goto free_stats;
  
  	ret = gro_cells_init(&t->gro_cells, dev);
  	if (ret)
  		goto destroy_dst;
cdf3464e6   Martin KaFai Lau   ipv6: Fix dst_ent...
1821

79ecb90e6   Tom Herbert   ipv6: Generic tun...
1822
  	t->tun_hlen = 0;
058214a4d   Tom Herbert   ip6_tun: Add infr...
1823
1824
1825
1826
1827
1828
1829
1830
  	t->hlen = t->encap_hlen + t->tun_hlen;
  	t_hlen = t->hlen + sizeof(struct ipv6hdr);
  
  	dev->type = ARPHRD_TUNNEL6;
  	dev->hard_header_len = LL_MAX_HEADER + t_hlen;
  	dev->mtu = ETH_DATA_LEN - t_hlen;
  	if (!(t->parms.flags & IP6_TNL_F_IGN_ENCAP_LIMIT))
  		dev->mtu -= 8;
b96f9afee   Jarod Wilson   ipv4/6: use core ...
1831
  	dev->min_mtu = ETH_MIN_MTU;
f7ff1fde9   Nicolas Dichtel   ip6_tunnel: remov...
1832
  	dev->max_mtu = IP6_MAX_MTU - dev->hard_header_len;
79ecb90e6   Tom Herbert   ipv6: Generic tun...
1833

8560f2266   Eric Dumazet   ip6tnl: percpu st...
1834
  	return 0;
0d3c703a9   Tom Herbert   ipv6: Cleanup IPv...
1835
1836
1837
1838
1839
1840
1841
1842
  
  destroy_dst:
  	dst_cache_destroy(&t->dst_cache);
  free_stats:
  	free_percpu(dev->tstats);
  	dev->tstats = NULL;
  
  	return ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1843
1844
1845
  }
  
  /**
3144581cb   Yasuyuki Kozakai   [IPV6] IP6TUNNEL:...
1846
   * ip6_tnl_dev_init - initializer for all non fallback tunnel devices
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1847
1848
   *   @dev: virtual device associated with tunnel
   **/
8560f2266   Eric Dumazet   ip6tnl: percpu st...
1849
  static int ip6_tnl_dev_init(struct net_device *dev)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1850
  {
2941a4863   Patrick McHardy   [NET]: Convert ne...
1851
  	struct ip6_tnl *t = netdev_priv(dev);
8560f2266   Eric Dumazet   ip6tnl: percpu st...
1852
1853
1854
1855
  	int err = ip6_tnl_dev_init_gen(dev);
  
  	if (err)
  		return err;
3144581cb   Yasuyuki Kozakai   [IPV6] IP6TUNNEL:...
1856
  	ip6_tnl_link_config(t);
5311a69aa   William Dauchy   net, ip6_tunnel: ...
1857
  	if (t->parms.collect_md)
8d79266bc   Alexei Starovoitov   ip6_tunnel: add c...
1858
  		netif_keep_dst(dev);
8560f2266   Eric Dumazet   ip6tnl: percpu st...
1859
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1860
1861
1862
  }
  
  /**
3144581cb   Yasuyuki Kozakai   [IPV6] IP6TUNNEL:...
1863
   * ip6_fb_tnl_dev_init - initializer for fallback tunnel device
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1864
1865
1866
1867
   *   @dev: fallback device
   *
   * Return: 0
   **/
8560f2266   Eric Dumazet   ip6tnl: percpu st...
1868
  static int __net_init ip6_fb_tnl_dev_init(struct net_device *dev)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1869
  {
2941a4863   Patrick McHardy   [NET]: Convert ne...
1870
  	struct ip6_tnl *t = netdev_priv(dev);
3e6c9fb5f   Pavel Emelyanov   [IP6TUNNEL]: Make...
1871
1872
  	struct net *net = dev_net(dev);
  	struct ip6_tnl_net *ip6n = net_generic(net, ip6_tnl_net_id);
502b09356   Yasuyuki Kozakai   [IPV6] IP6TUNNEL:...
1873
  	t->parms.proto = IPPROTO_IPV6;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1874
  	dev_hold(dev);
d0087b29f   Ville Nuorvala   ipv6_tunnel: Allo...
1875

cf778b00e   Eric Dumazet   net: reintroduce ...
1876
  	rcu_assign_pointer(ip6n->tnls_wc[0], t);
8560f2266   Eric Dumazet   ip6tnl: percpu st...
1877
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1878
  }
a8b8a889e   Matthias Schiffer   net: add netlink_...
1879
1880
  static int ip6_tnl_validate(struct nlattr *tb[], struct nlattr *data[],
  			    struct netlink_ext_ack *extack)
0b1124572   Nicolas Dichtel   ip6tnl: add suppo...
1881
1882
  {
  	u8 proto;
c8965932a   Susant Sahani   ip6_tunnel: fix p...
1883
  	if (!data || !data[IFLA_IPTUN_PROTO])
0b1124572   Nicolas Dichtel   ip6tnl: add suppo...
1884
1885
1886
1887
1888
1889
1890
1891
1892
1893
1894
1895
1896
1897
1898
1899
1900
1901
1902
1903
1904
1905
1906
  		return 0;
  
  	proto = nla_get_u8(data[IFLA_IPTUN_PROTO]);
  	if (proto != IPPROTO_IPV6 &&
  	    proto != IPPROTO_IPIP &&
  	    proto != 0)
  		return -EINVAL;
  
  	return 0;
  }
  
  static void ip6_tnl_netlink_parms(struct nlattr *data[],
  				  struct __ip6_tnl_parm *parms)
  {
  	memset(parms, 0, sizeof(*parms));
  
  	if (!data)
  		return;
  
  	if (data[IFLA_IPTUN_LINK])
  		parms->link = nla_get_u32(data[IFLA_IPTUN_LINK]);
  
  	if (data[IFLA_IPTUN_LOCAL])
67b61f6c1   Jiri Benc   netlink: implemen...
1907
  		parms->laddr = nla_get_in6_addr(data[IFLA_IPTUN_LOCAL]);
0b1124572   Nicolas Dichtel   ip6tnl: add suppo...
1908
1909
  
  	if (data[IFLA_IPTUN_REMOTE])
67b61f6c1   Jiri Benc   netlink: implemen...
1910
  		parms->raddr = nla_get_in6_addr(data[IFLA_IPTUN_REMOTE]);
0b1124572   Nicolas Dichtel   ip6tnl: add suppo...
1911
1912
1913
1914
1915
1916
1917
1918
  
  	if (data[IFLA_IPTUN_TTL])
  		parms->hop_limit = nla_get_u8(data[IFLA_IPTUN_TTL]);
  
  	if (data[IFLA_IPTUN_ENCAP_LIMIT])
  		parms->encap_limit = nla_get_u8(data[IFLA_IPTUN_ENCAP_LIMIT]);
  
  	if (data[IFLA_IPTUN_FLOWINFO])
1ff05fb71   Nicolas Dichtel   ip6tnl: fix spars...
1919
  		parms->flowinfo = nla_get_be32(data[IFLA_IPTUN_FLOWINFO]);
0b1124572   Nicolas Dichtel   ip6tnl: add suppo...
1920
1921
1922
1923
1924
1925
  
  	if (data[IFLA_IPTUN_FLAGS])
  		parms->flags = nla_get_u32(data[IFLA_IPTUN_FLAGS]);
  
  	if (data[IFLA_IPTUN_PROTO])
  		parms->proto = nla_get_u8(data[IFLA_IPTUN_PROTO]);
8d79266bc   Alexei Starovoitov   ip6_tunnel: add c...
1926
1927
1928
  
  	if (data[IFLA_IPTUN_COLLECT_METADATA])
  		parms->collect_md = true;
0a473b82c   Craig Gallek   ip6_tunnel: Allow...
1929
1930
1931
  
  	if (data[IFLA_IPTUN_FWMARK])
  		parms->fwmark = nla_get_u32(data[IFLA_IPTUN_FWMARK]);
0b1124572   Nicolas Dichtel   ip6tnl: add suppo...
1932
  }
b3a27b519   Tom Herbert   ip6_tunnel: Add s...
1933
1934
1935
1936
1937
1938
1939
1940
1941
1942
1943
1944
1945
1946
1947
1948
1949
1950
1951
1952
1953
1954
1955
1956
1957
1958
1959
1960
1961
1962
1963
1964
  static bool ip6_tnl_netlink_encap_parms(struct nlattr *data[],
  					struct ip_tunnel_encap *ipencap)
  {
  	bool ret = false;
  
  	memset(ipencap, 0, sizeof(*ipencap));
  
  	if (!data)
  		return ret;
  
  	if (data[IFLA_IPTUN_ENCAP_TYPE]) {
  		ret = true;
  		ipencap->type = nla_get_u16(data[IFLA_IPTUN_ENCAP_TYPE]);
  	}
  
  	if (data[IFLA_IPTUN_ENCAP_FLAGS]) {
  		ret = true;
  		ipencap->flags = nla_get_u16(data[IFLA_IPTUN_ENCAP_FLAGS]);
  	}
  
  	if (data[IFLA_IPTUN_ENCAP_SPORT]) {
  		ret = true;
  		ipencap->sport = nla_get_be16(data[IFLA_IPTUN_ENCAP_SPORT]);
  	}
  
  	if (data[IFLA_IPTUN_ENCAP_DPORT]) {
  		ret = true;
  		ipencap->dport = nla_get_be16(data[IFLA_IPTUN_ENCAP_DPORT]);
  	}
  
  	return ret;
  }
0b1124572   Nicolas Dichtel   ip6tnl: add suppo...
1965
  static int ip6_tnl_newlink(struct net *src_net, struct net_device *dev,
7a3f4a185   Matthias Schiffer   net: add netlink_...
1966
1967
  			   struct nlattr *tb[], struct nlattr *data[],
  			   struct netlink_ext_ack *extack)
0b1124572   Nicolas Dichtel   ip6tnl: add suppo...
1968
1969
  {
  	struct net *net = dev_net(dev);
8d79266bc   Alexei Starovoitov   ip6_tunnel: add c...
1970
  	struct ip6_tnl_net *ip6n = net_generic(net, ip6_tnl_net_id);
b3a27b519   Tom Herbert   ip6_tunnel: Add s...
1971
  	struct ip_tunnel_encap ipencap;
a6aa80446   Xin Long   ip6_tunnel: fix I...
1972
1973
  	struct ip6_tnl *nt, *t;
  	int err;
0b1124572   Nicolas Dichtel   ip6tnl: add suppo...
1974
1975
  
  	nt = netdev_priv(dev);
b3a27b519   Tom Herbert   ip6_tunnel: Add s...
1976
1977
  
  	if (ip6_tnl_netlink_encap_parms(data, &ipencap)) {
a6aa80446   Xin Long   ip6_tunnel: fix I...
1978
  		err = ip6_tnl_encap_setup(nt, &ipencap);
b3a27b519   Tom Herbert   ip6_tunnel: Add s...
1979
1980
1981
  		if (err < 0)
  			return err;
  	}
0b1124572   Nicolas Dichtel   ip6tnl: add suppo...
1982
  	ip6_tnl_netlink_parms(data, &nt->parms);
8d79266bc   Alexei Starovoitov   ip6_tunnel: add c...
1983
1984
1985
1986
1987
1988
1989
1990
  	if (nt->parms.collect_md) {
  		if (rtnl_dereference(ip6n->collect_md_tun))
  			return -EEXIST;
  	} else {
  		t = ip6_tnl_locate(net, &nt->parms, 0);
  		if (!IS_ERR(t))
  			return -EEXIST;
  	}
0b1124572   Nicolas Dichtel   ip6tnl: add suppo...
1991

a6aa80446   Xin Long   ip6_tunnel: fix I...
1992
1993
1994
1995
1996
  	err = ip6_tnl_create2(dev);
  	if (!err && tb[IFLA_MTU])
  		ip6_tnl_change_mtu(dev, nla_get_u32(tb[IFLA_MTU]));
  
  	return err;
0b1124572   Nicolas Dichtel   ip6tnl: add suppo...
1997
1998
1999
  }
  
  static int ip6_tnl_changelink(struct net_device *dev, struct nlattr *tb[],
ad744b223   Matthias Schiffer   net: add netlink_...
2000
2001
  			      struct nlattr *data[],
  			      struct netlink_ext_ack *extack)
0b1124572   Nicolas Dichtel   ip6tnl: add suppo...
2002
  {
0bd876282   Nicolas Dichtel   ip6tnl: add x-net...
2003
  	struct ip6_tnl *t = netdev_priv(dev);
0b1124572   Nicolas Dichtel   ip6tnl: add suppo...
2004
  	struct __ip6_tnl_parm p;
0bd876282   Nicolas Dichtel   ip6tnl: add x-net...
2005
  	struct net *net = t->net;
0b1124572   Nicolas Dichtel   ip6tnl: add suppo...
2006
  	struct ip6_tnl_net *ip6n = net_generic(net, ip6_tnl_net_id);
b3a27b519   Tom Herbert   ip6_tunnel: Add s...
2007
  	struct ip_tunnel_encap ipencap;
0b1124572   Nicolas Dichtel   ip6tnl: add suppo...
2008
2009
2010
  
  	if (dev == ip6n->fb_tnl_dev)
  		return -EINVAL;
b3a27b519   Tom Herbert   ip6_tunnel: Add s...
2011
2012
2013
2014
2015
2016
  	if (ip6_tnl_netlink_encap_parms(data, &ipencap)) {
  		int err = ip6_tnl_encap_setup(t, &ipencap);
  
  		if (err < 0)
  			return err;
  	}
0b1124572   Nicolas Dichtel   ip6tnl: add suppo...
2017
  	ip6_tnl_netlink_parms(data, &p);
8d79266bc   Alexei Starovoitov   ip6_tunnel: add c...
2018
2019
  	if (p.collect_md)
  		return -EINVAL;
0b1124572   Nicolas Dichtel   ip6tnl: add suppo...
2020
2021
  
  	t = ip6_tnl_locate(net, &p, 0);
37355565b   Nicolas Dichtel   ip6_tunnel: fix e...
2022
  	if (!IS_ERR(t)) {
0b1124572   Nicolas Dichtel   ip6tnl: add suppo...
2023
2024
2025
2026
2027
2028
2029
  		if (t->dev != dev)
  			return -EEXIST;
  	} else
  		t = netdev_priv(dev);
  
  	return ip6_tnl_update(t, &p);
  }
1e9f3d6f1   Nicolas Dichtel   ip6tnl: fix use a...
2030
2031
2032
2033
2034
2035
2036
2037
  static void ip6_tnl_dellink(struct net_device *dev, struct list_head *head)
  {
  	struct net *net = dev_net(dev);
  	struct ip6_tnl_net *ip6n = net_generic(net, ip6_tnl_net_id);
  
  	if (dev != ip6n->fb_tnl_dev)
  		unregister_netdevice_queue(dev, head);
  }
b58d731ac   Nicolas Dichtel   ip6tnl: rename rt...
2038
  static size_t ip6_tnl_get_size(const struct net_device *dev)
c075b1309   Nicolas Dichtel   ip6tnl: advertise...
2039
2040
2041
2042
2043
2044
2045
2046
2047
2048
2049
2050
2051
2052
2053
2054
  {
  	return
  		/* IFLA_IPTUN_LINK */
  		nla_total_size(4) +
  		/* IFLA_IPTUN_LOCAL */
  		nla_total_size(sizeof(struct in6_addr)) +
  		/* IFLA_IPTUN_REMOTE */
  		nla_total_size(sizeof(struct in6_addr)) +
  		/* IFLA_IPTUN_TTL */
  		nla_total_size(1) +
  		/* IFLA_IPTUN_ENCAP_LIMIT */
  		nla_total_size(1) +
  		/* IFLA_IPTUN_FLOWINFO */
  		nla_total_size(4) +
  		/* IFLA_IPTUN_FLAGS */
  		nla_total_size(4) +
cfa323b6b   Nicolas Dichtel   ip6tnl/rtnl: add ...
2055
2056
  		/* IFLA_IPTUN_PROTO */
  		nla_total_size(1) +
b3a27b519   Tom Herbert   ip6_tunnel: Add s...
2057
2058
2059
2060
2061
2062
2063
2064
  		/* IFLA_IPTUN_ENCAP_TYPE */
  		nla_total_size(2) +
  		/* IFLA_IPTUN_ENCAP_FLAGS */
  		nla_total_size(2) +
  		/* IFLA_IPTUN_ENCAP_SPORT */
  		nla_total_size(2) +
  		/* IFLA_IPTUN_ENCAP_DPORT */
  		nla_total_size(2) +
8d79266bc   Alexei Starovoitov   ip6_tunnel: add c...
2065
2066
  		/* IFLA_IPTUN_COLLECT_METADATA */
  		nla_total_size(0) +
0a473b82c   Craig Gallek   ip6_tunnel: Allow...
2067
2068
  		/* IFLA_IPTUN_FWMARK */
  		nla_total_size(4) +
c075b1309   Nicolas Dichtel   ip6tnl: advertise...
2069
2070
  		0;
  }
b58d731ac   Nicolas Dichtel   ip6tnl: rename rt...
2071
  static int ip6_tnl_fill_info(struct sk_buff *skb, const struct net_device *dev)
c075b1309   Nicolas Dichtel   ip6tnl: advertise...
2072
2073
2074
2075
2076
  {
  	struct ip6_tnl *tunnel = netdev_priv(dev);
  	struct __ip6_tnl_parm *parm = &tunnel->parms;
  
  	if (nla_put_u32(skb, IFLA_IPTUN_LINK, parm->link) ||
930345ea6   Jiri Benc   netlink: implemen...
2077
2078
  	    nla_put_in6_addr(skb, IFLA_IPTUN_LOCAL, &parm->laddr) ||
  	    nla_put_in6_addr(skb, IFLA_IPTUN_REMOTE, &parm->raddr) ||
c075b1309   Nicolas Dichtel   ip6tnl: advertise...
2079
2080
2081
  	    nla_put_u8(skb, IFLA_IPTUN_TTL, parm->hop_limit) ||
  	    nla_put_u8(skb, IFLA_IPTUN_ENCAP_LIMIT, parm->encap_limit) ||
  	    nla_put_be32(skb, IFLA_IPTUN_FLOWINFO, parm->flowinfo) ||
cfa323b6b   Nicolas Dichtel   ip6tnl/rtnl: add ...
2082
  	    nla_put_u32(skb, IFLA_IPTUN_FLAGS, parm->flags) ||
0a473b82c   Craig Gallek   ip6_tunnel: Allow...
2083
2084
  	    nla_put_u8(skb, IFLA_IPTUN_PROTO, parm->proto) ||
  	    nla_put_u32(skb, IFLA_IPTUN_FWMARK, parm->fwmark))
c075b1309   Nicolas Dichtel   ip6tnl: advertise...
2085
  		goto nla_put_failure;
b3a27b519   Tom Herbert   ip6_tunnel: Add s...
2086

8d79266bc   Alexei Starovoitov   ip6_tunnel: add c...
2087
2088
2089
2090
  	if (nla_put_u16(skb, IFLA_IPTUN_ENCAP_TYPE, tunnel->encap.type) ||
  	    nla_put_be16(skb, IFLA_IPTUN_ENCAP_SPORT, tunnel->encap.sport) ||
  	    nla_put_be16(skb, IFLA_IPTUN_ENCAP_DPORT, tunnel->encap.dport) ||
  	    nla_put_u16(skb, IFLA_IPTUN_ENCAP_FLAGS, tunnel->encap.flags))
b3a27b519   Tom Herbert   ip6_tunnel: Add s...
2091
  		goto nla_put_failure;
8d79266bc   Alexei Starovoitov   ip6_tunnel: add c...
2092
2093
2094
  	if (parm->collect_md)
  		if (nla_put_flag(skb, IFLA_IPTUN_COLLECT_METADATA))
  			goto nla_put_failure;
0a473b82c   Craig Gallek   ip6_tunnel: Allow...
2095

c075b1309   Nicolas Dichtel   ip6tnl: advertise...
2096
2097
2098
2099
2100
  	return 0;
  
  nla_put_failure:
  	return -EMSGSIZE;
  }
1728d4fab   Nicolas Dichtel   tunnels: advertis...
2101
2102
2103
2104
2105
2106
2107
  struct net *ip6_tnl_get_link_net(const struct net_device *dev)
  {
  	struct ip6_tnl *tunnel = netdev_priv(dev);
  
  	return tunnel->net;
  }
  EXPORT_SYMBOL(ip6_tnl_get_link_net);
0b1124572   Nicolas Dichtel   ip6tnl: add suppo...
2108
2109
2110
2111
2112
2113
2114
2115
2116
  static const struct nla_policy ip6_tnl_policy[IFLA_IPTUN_MAX + 1] = {
  	[IFLA_IPTUN_LINK]		= { .type = NLA_U32 },
  	[IFLA_IPTUN_LOCAL]		= { .len = sizeof(struct in6_addr) },
  	[IFLA_IPTUN_REMOTE]		= { .len = sizeof(struct in6_addr) },
  	[IFLA_IPTUN_TTL]		= { .type = NLA_U8 },
  	[IFLA_IPTUN_ENCAP_LIMIT]	= { .type = NLA_U8 },
  	[IFLA_IPTUN_FLOWINFO]		= { .type = NLA_U32 },
  	[IFLA_IPTUN_FLAGS]		= { .type = NLA_U32 },
  	[IFLA_IPTUN_PROTO]		= { .type = NLA_U8 },
b3a27b519   Tom Herbert   ip6_tunnel: Add s...
2117
2118
2119
2120
  	[IFLA_IPTUN_ENCAP_TYPE]		= { .type = NLA_U16 },
  	[IFLA_IPTUN_ENCAP_FLAGS]	= { .type = NLA_U16 },
  	[IFLA_IPTUN_ENCAP_SPORT]	= { .type = NLA_U16 },
  	[IFLA_IPTUN_ENCAP_DPORT]	= { .type = NLA_U16 },
8d79266bc   Alexei Starovoitov   ip6_tunnel: add c...
2121
  	[IFLA_IPTUN_COLLECT_METADATA]	= { .type = NLA_FLAG },
0a473b82c   Craig Gallek   ip6_tunnel: Allow...
2122
  	[IFLA_IPTUN_FWMARK]		= { .type = NLA_U32 },
0b1124572   Nicolas Dichtel   ip6tnl: add suppo...
2123
  };
c075b1309   Nicolas Dichtel   ip6tnl: advertise...
2124
2125
2126
  static struct rtnl_link_ops ip6_link_ops __read_mostly = {
  	.kind		= "ip6tnl",
  	.maxtype	= IFLA_IPTUN_MAX,
0b1124572   Nicolas Dichtel   ip6tnl: add suppo...
2127
  	.policy		= ip6_tnl_policy,
c075b1309   Nicolas Dichtel   ip6tnl: advertise...
2128
  	.priv_size	= sizeof(struct ip6_tnl),
0b1124572   Nicolas Dichtel   ip6tnl: add suppo...
2129
2130
2131
2132
  	.setup		= ip6_tnl_dev_setup,
  	.validate	= ip6_tnl_validate,
  	.newlink	= ip6_tnl_newlink,
  	.changelink	= ip6_tnl_changelink,
1e9f3d6f1   Nicolas Dichtel   ip6tnl: fix use a...
2133
  	.dellink	= ip6_tnl_dellink,
b58d731ac   Nicolas Dichtel   ip6tnl: rename rt...
2134
2135
  	.get_size	= ip6_tnl_get_size,
  	.fill_info	= ip6_tnl_fill_info,
1728d4fab   Nicolas Dichtel   tunnels: advertis...
2136
  	.get_link_net	= ip6_tnl_get_link_net,
c075b1309   Nicolas Dichtel   ip6tnl: advertise...
2137
  };
3ff2cfa55   Eric Dumazet   ipv6: struct xfrm...
2138
  static struct xfrm6_tunnel ip4ip6_handler __read_mostly = {
c4d3efafc   Yasuyuki Kozakai   [IPV6] IP6TUNNEL:...
2139
2140
2141
2142
  	.handler	= ip4ip6_rcv,
  	.err_handler	= ip4ip6_err,
  	.priority	=	1,
  };
3ff2cfa55   Eric Dumazet   ipv6: struct xfrm...
2143
  static struct xfrm6_tunnel ip6ip6_handler __read_mostly = {
0303770de   Patrick McHardy   [NET]: Make ipip/...
2144
2145
  	.handler	= ip6ip6_rcv,
  	.err_handler	= ip6ip6_err,
d2acc3479   Herbert Xu   [INET]: Introduce...
2146
  	.priority	=	1,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2147
  };
f200e98d9   Vadim Fedorenko   ip6_tunnel: add g...
2148
2149
2150
2151
2152
  static struct xfrm6_tunnel mplsip6_handler __read_mostly = {
  	.handler	= mplsip6_rcv,
  	.err_handler	= mplsip6_err,
  	.priority	=	1,
  };
bb401caef   Eric Dumazet   ipv6: speedup ipv...
2153
  static void __net_exit ip6_tnl_destroy_tunnels(struct net *net, struct list_head *list)
3e6c9fb5f   Pavel Emelyanov   [IP6TUNNEL]: Make...
2154
  {
1e9f3d6f1   Nicolas Dichtel   ip6tnl: fix use a...
2155
  	struct ip6_tnl_net *ip6n = net_generic(net, ip6_tnl_net_id);
0bd876282   Nicolas Dichtel   ip6tnl: add x-net...
2156
  	struct net_device *dev, *aux;
3e6c9fb5f   Pavel Emelyanov   [IP6TUNNEL]: Make...
2157
2158
  	int h;
  	struct ip6_tnl *t;
0bd876282   Nicolas Dichtel   ip6tnl: add x-net...
2159
2160
  	for_each_netdev_safe(net, dev, aux)
  		if (dev->rtnl_link_ops == &ip6_link_ops)
bb401caef   Eric Dumazet   ipv6: speedup ipv...
2161
  			unregister_netdevice_queue(dev, list);
0bd876282   Nicolas Dichtel   ip6tnl: add x-net...
2162

e87a8f24c   Jiri Kosina   net: resolve symb...
2163
  	for (h = 0; h < IP6_TUNNEL_HASH_SIZE; h++) {
947676326   Eric Dumazet   ip6tnl: get rid o...
2164
  		t = rtnl_dereference(ip6n->tnls_r_l[h]);
53b24b8f9   Ian Morris   ipv6: coding styl...
2165
  		while (t) {
0bd876282   Nicolas Dichtel   ip6tnl: add x-net...
2166
2167
2168
2169
  			/* If dev is in the same netns, it has already
  			 * been added to the list by the previous loop.
  			 */
  			if (!net_eq(dev_net(t->dev), net))
bb401caef   Eric Dumazet   ipv6: speedup ipv...
2170
  				unregister_netdevice_queue(t->dev, list);
947676326   Eric Dumazet   ip6tnl: get rid o...
2171
  			t = rtnl_dereference(t->next);
cf4432f55   Eric Dumazet   ip6tnl: Optimize ...
2172
  		}
3e6c9fb5f   Pavel Emelyanov   [IP6TUNNEL]: Make...
2173
  	}
3e6c9fb5f   Pavel Emelyanov   [IP6TUNNEL]: Make...
2174
  }
2c8c1e729   Alexey Dobriyan   net: spread __net...
2175
  static int __net_init ip6_tnl_init_net(struct net *net)
13eeb8e92   Pavel Emelyanov   [IP6TUNNEL]: Intr...
2176
  {
ac31cd3cb   Eric W. Biederman   net: Simplify ip6...
2177
  	struct ip6_tnl_net *ip6n = net_generic(net, ip6_tnl_net_id);
731abb9cb   Josh Boyer   ip6_tunnel: copy ...
2178
  	struct ip6_tnl *t = NULL;
13eeb8e92   Pavel Emelyanov   [IP6TUNNEL]: Intr...
2179
  	int err;
13eeb8e92   Pavel Emelyanov   [IP6TUNNEL]: Intr...
2180

3e6c9fb5f   Pavel Emelyanov   [IP6TUNNEL]: Make...
2181
2182
  	ip6n->tnls[0] = ip6n->tnls_wc;
  	ip6n->tnls[1] = ip6n->tnls_r_l;
79134e6ce   Eric Dumazet   net: do not creat...
2183
2184
  	if (!net_has_fallback_tunnels(net))
  		return 0;
15820e129   Pavel Emelyanov   [IP6TUNNEL]: Make...
2185
2186
  	err = -ENOMEM;
  	ip6n->fb_tnl_dev = alloc_netdev(sizeof(struct ip6_tnl), "ip6tnl0",
c835a6773   Tom Gundersen   net: set name_ass...
2187
  					NET_NAME_UNKNOWN, ip6_tnl_dev_setup);
15820e129   Pavel Emelyanov   [IP6TUNNEL]: Make...
2188
2189
2190
  
  	if (!ip6n->fb_tnl_dev)
  		goto err_alloc_dev;
be77e5930   Alexey Dobriyan   net: fix tunnels ...
2191
  	dev_net_set(ip6n->fb_tnl_dev, net);
bb8140947   Nicolas Dichtel   ip6tnl: allow to ...
2192
  	ip6n->fb_tnl_dev->rtnl_link_ops = &ip6_link_ops;
0bd876282   Nicolas Dichtel   ip6tnl: add x-net...
2193
2194
2195
2196
  	/* FB netdevice is special: we have one, and only one per netns.
  	 * Allowing to move it to another netns is clearly unsafe.
  	 */
  	ip6n->fb_tnl_dev->features |= NETIF_F_NETNS_LOCAL;
15820e129   Pavel Emelyanov   [IP6TUNNEL]: Make...
2197

8560f2266   Eric Dumazet   ip6tnl: percpu st...
2198
2199
2200
  	err = ip6_fb_tnl_dev_init(ip6n->fb_tnl_dev);
  	if (err < 0)
  		goto err_register;
15820e129   Pavel Emelyanov   [IP6TUNNEL]: Make...
2201
2202
2203
2204
  
  	err = register_netdev(ip6n->fb_tnl_dev);
  	if (err < 0)
  		goto err_register;
731abb9cb   Josh Boyer   ip6_tunnel: copy ...
2205
2206
2207
2208
  
  	t = netdev_priv(ip6n->fb_tnl_dev);
  
  	strcpy(t->parms.name, ip6n->fb_tnl_dev->name);
13eeb8e92   Pavel Emelyanov   [IP6TUNNEL]: Intr...
2209
  	return 0;
15820e129   Pavel Emelyanov   [IP6TUNNEL]: Make...
2210
  err_register:
cf124db56   David S. Miller   net: Fix inconsis...
2211
  	free_netdev(ip6n->fb_tnl_dev);
15820e129   Pavel Emelyanov   [IP6TUNNEL]: Make...
2212
  err_alloc_dev:
13eeb8e92   Pavel Emelyanov   [IP6TUNNEL]: Intr...
2213
2214
  	return err;
  }
bb401caef   Eric Dumazet   ipv6: speedup ipv...
2215
  static void __net_exit ip6_tnl_exit_batch_net(struct list_head *net_list)
13eeb8e92   Pavel Emelyanov   [IP6TUNNEL]: Intr...
2216
  {
bb401caef   Eric Dumazet   ipv6: speedup ipv...
2217
2218
  	struct net *net;
  	LIST_HEAD(list);
3e6c9fb5f   Pavel Emelyanov   [IP6TUNNEL]: Make...
2219
  	rtnl_lock();
bb401caef   Eric Dumazet   ipv6: speedup ipv...
2220
2221
2222
  	list_for_each_entry(net, net_list, exit_list)
  		ip6_tnl_destroy_tunnels(net, &list);
  	unregister_netdevice_many(&list);
3e6c9fb5f   Pavel Emelyanov   [IP6TUNNEL]: Make...
2223
  	rtnl_unlock();
13eeb8e92   Pavel Emelyanov   [IP6TUNNEL]: Intr...
2224
2225
2226
2227
  }
  
  static struct pernet_operations ip6_tnl_net_ops = {
  	.init = ip6_tnl_init_net,
bb401caef   Eric Dumazet   ipv6: speedup ipv...
2228
  	.exit_batch = ip6_tnl_exit_batch_net,
ac31cd3cb   Eric W. Biederman   net: Simplify ip6...
2229
2230
  	.id   = &ip6_tnl_net_id,
  	.size = sizeof(struct ip6_tnl_net),
13eeb8e92   Pavel Emelyanov   [IP6TUNNEL]: Intr...
2231
  };
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2232
2233
2234
2235
2236
2237
2238
2239
2240
  /**
   * ip6_tunnel_init - register protocol and reserve needed resources
   *
   * Return: 0 on success
   **/
  
  static int __init ip6_tunnel_init(void)
  {
  	int  err;
8c22dab03   Xin Long   ip6_tunnel: do no...
2241
2242
  	if (!ipv6_mod_enabled())
  		return -EOPNOTSUPP;
d5aa407f5   Alexey Dobriyan   tunnels: fix netn...
2243
2244
2245
2246
2247
2248
  	err = register_pernet_device(&ip6_tnl_net_ops);
  	if (err < 0)
  		goto out_pernet;
  
  	err = xfrm6_tunnel_register(&ip4ip6_handler, AF_INET);
  	if (err < 0) {
f32138319   Joe Perches   net: ipv6: Standa...
2249
2250
  		pr_err("%s: can't register ip4ip6
  ", __func__);
d5aa407f5   Alexey Dobriyan   tunnels: fix netn...
2251
  		goto out_ip4ip6;
c4d3efafc   Yasuyuki Kozakai   [IPV6] IP6TUNNEL:...
2252
  	}
d5aa407f5   Alexey Dobriyan   tunnels: fix netn...
2253
2254
  	err = xfrm6_tunnel_register(&ip6ip6_handler, AF_INET6);
  	if (err < 0) {
f32138319   Joe Perches   net: ipv6: Standa...
2255
2256
  		pr_err("%s: can't register ip6ip6
  ", __func__);
d5aa407f5   Alexey Dobriyan   tunnels: fix netn...
2257
  		goto out_ip6ip6;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2258
  	}
f200e98d9   Vadim Fedorenko   ip6_tunnel: add g...
2259
2260
2261
2262
2263
2264
2265
2266
2267
  
  	if (ip6_tnl_mpls_supported()) {
  		err = xfrm6_tunnel_register(&mplsip6_handler, AF_MPLS);
  		if (err < 0) {
  			pr_err("%s: can't register mplsip6
  ", __func__);
  			goto out_mplsip6;
  		}
  	}
c075b1309   Nicolas Dichtel   ip6tnl: advertise...
2268
2269
2270
  	err = rtnl_link_register(&ip6_link_ops);
  	if (err < 0)
  		goto rtnl_link_failed;
13eeb8e92   Pavel Emelyanov   [IP6TUNNEL]: Intr...
2271

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2272
  	return 0;
d5aa407f5   Alexey Dobriyan   tunnels: fix netn...
2273

c075b1309   Nicolas Dichtel   ip6tnl: advertise...
2274
  rtnl_link_failed:
f200e98d9   Vadim Fedorenko   ip6_tunnel: add g...
2275
2276
2277
  	if (ip6_tnl_mpls_supported())
  		xfrm6_tunnel_deregister(&mplsip6_handler, AF_MPLS);
  out_mplsip6:
c075b1309   Nicolas Dichtel   ip6tnl: advertise...
2278
  	xfrm6_tunnel_deregister(&ip6ip6_handler, AF_INET6);
d5aa407f5   Alexey Dobriyan   tunnels: fix netn...
2279
  out_ip6ip6:
c4d3efafc   Yasuyuki Kozakai   [IPV6] IP6TUNNEL:...
2280
  	xfrm6_tunnel_deregister(&ip4ip6_handler, AF_INET);
d5aa407f5   Alexey Dobriyan   tunnels: fix netn...
2281
2282
2283
  out_ip4ip6:
  	unregister_pernet_device(&ip6_tnl_net_ops);
  out_pernet:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2284
2285
2286
2287
2288
2289
2290
2291
2292
  	return err;
  }
  
  /**
   * ip6_tunnel_cleanup - free resources and unregister protocol
   **/
  
  static void __exit ip6_tunnel_cleanup(void)
  {
c075b1309   Nicolas Dichtel   ip6tnl: advertise...
2293
  	rtnl_link_unregister(&ip6_link_ops);
c4d3efafc   Yasuyuki Kozakai   [IPV6] IP6TUNNEL:...
2294
  	if (xfrm6_tunnel_deregister(&ip4ip6_handler, AF_INET))
f32138319   Joe Perches   net: ipv6: Standa...
2295
2296
  		pr_info("%s: can't deregister ip4ip6
  ", __func__);
c4d3efafc   Yasuyuki Kozakai   [IPV6] IP6TUNNEL:...
2297

73d605d1a   Kazunori MIYAZAWA   [IPSEC]: changing...
2298
  	if (xfrm6_tunnel_deregister(&ip6ip6_handler, AF_INET6))
f32138319   Joe Perches   net: ipv6: Standa...
2299
2300
  		pr_info("%s: can't deregister ip6ip6
  ", __func__);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2301

f200e98d9   Vadim Fedorenko   ip6_tunnel: add g...
2302
2303
2304
2305
  	if (ip6_tnl_mpls_supported() &&
  	    xfrm6_tunnel_deregister(&mplsip6_handler, AF_MPLS))
  		pr_info("%s: can't deregister mplsip6
  ", __func__);
ac31cd3cb   Eric W. Biederman   net: Simplify ip6...
2306
  	unregister_pernet_device(&ip6_tnl_net_ops);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2307
2308
2309
2310
  }
  
  module_init(ip6_tunnel_init);
  module_exit(ip6_tunnel_cleanup);