Blame view

net/ipv6/ip6_tunnel.c 43.2 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
  /*
c4d3efafc   Yasuyuki Kozakai   [IPV6] IP6TUNNEL:...
2
   *	IPv6 tunneling device
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3
4
5
   *	Linux INET6 implementation
   *
   *	Authors:
1ab1457c4   YOSHIFUJI Hideaki   [NET] IPV6: Fix w...
6
   *	Ville Nuorvala		<vnuorval@tcs.hut.fi>
c4d3efafc   Yasuyuki Kozakai   [IPV6] IP6TUNNEL:...
7
   *	Yasuyuki Kozakai	<kozakai@linux-ipv6.org>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
8
   *
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
9
   *      Based on:
c4d3efafc   Yasuyuki Kozakai   [IPV6] IP6TUNNEL:...
10
   *      linux/net/ipv6/sit.c and linux/net/ipv4/ipip.c
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
11
12
13
14
15
16
17
18
19
   *
   *      RFC 2473
   *
   *	This program is free software; you can redistribute it and/or
   *      modify it under the terms of the GNU General Public License
   *      as published by the Free Software Foundation; either version
   *      2 of the License, or (at your option) any later version.
   *
   */
f32138319   Joe Perches   net: ipv6: Standa...
20
  #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
21
  #include <linux/module.h>
4fc268d24   Randy Dunlap   [PATCH] capable/c...
22
  #include <linux/capability.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
23
24
25
  #include <linux/errno.h>
  #include <linux/types.h>
  #include <linux/sockios.h>
c4d3efafc   Yasuyuki Kozakai   [IPV6] IP6TUNNEL:...
26
  #include <linux/icmp.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
27
28
29
30
31
32
33
34
35
36
37
38
39
  #include <linux/if.h>
  #include <linux/in.h>
  #include <linux/ip.h>
  #include <linux/if_tunnel.h>
  #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: ...
40
  #include <linux/slab.h>
ddbe50320   Eric Dumazet   ipv6: add ipv6_ad...
41
  #include <linux/hash.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
42
43
  
  #include <asm/uaccess.h>
60063497a   Arun Sharma   atomic: use <linu...
44
  #include <linux/atomic.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
45

c4d3efafc   Yasuyuki Kozakai   [IPV6] IP6TUNNEL:...
46
  #include <net/icmp.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
47
  #include <net/ip.h>
c54419321   Pravin B Shelar   GRE: Refactor GRE...
48
  #include <net/ip_tunnels.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
49
  #include <net/ipv6.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
50
51
52
53
54
55
  #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...
56
57
  #include <net/net_namespace.h>
  #include <net/netns/generic.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
58
59
  
  MODULE_AUTHOR("Ville Nuorvala");
c4d3efafc   Yasuyuki Kozakai   [IPV6] IP6TUNNEL:...
60
  MODULE_DESCRIPTION("IPv6 tunneling device");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
61
  MODULE_LICENSE("GPL");
6dfbd87a2   stephen hemminger   ip6ip6: autoload ...
62
  MODULE_ALIAS_NETDEV("ip6tnl0");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
63

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
64
  #ifdef IP6_TNL_DEBUG
91df42bed   Joe Perches   net: ipv4 and ipv...
65
66
  #define IP6_TNL_TRACE(x...) pr_debug("%s:" x "
  ", __func__)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
67
68
69
70
71
  #else
  #define IP6_TNL_TRACE(x...) do {;} while(0)
  #endif
  
  #define IPV6_TCLASS_MASK (IPV6_FLOWINFO_MASK & ~IPV6_FLOWLABEL_MASK)
c4d3efafc   Yasuyuki Kozakai   [IPV6] IP6TUNNEL:...
72
  #define IPV6_TCLASS_SHIFT 20
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
73

ddbe50320   Eric Dumazet   ipv6: add ipv6_ad...
74
75
  #define HASH_SIZE_SHIFT  5
  #define HASH_SIZE (1 << HASH_SIZE_SHIFT)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
76

f4e0b4c5e   Nicolas Dichtel   ip6tnl/sit: drop ...
77
78
79
  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...
80
81
82
83
84
85
  static u32 HASH(const struct in6_addr *addr1, const struct in6_addr *addr2)
  {
  	u32 hash = ipv6_addr_hash(addr1) ^ ipv6_addr_hash(addr2);
  
  	return hash_32(hash, HASH_SIZE_SHIFT);
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
86

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

f99189b18   Eric Dumazet   netns: net_identi...
91
  static int ip6_tnl_net_id __read_mostly;
13eeb8e92   Pavel Emelyanov   [IP6TUNNEL]: Intr...
92
  struct ip6_tnl_net {
15820e129   Pavel Emelyanov   [IP6TUNNEL]: Make...
93
94
  	/* the IPv6 tunnel fallback device */
  	struct net_device *fb_tnl_dev;
3e6c9fb5f   Pavel Emelyanov   [IP6TUNNEL]: Make...
95
  	/* lists for storing tunnels in use */
947676326   Eric Dumazet   ip6tnl: get rid o...
96
97
98
  	struct ip6_tnl __rcu *tnls_r_l[HASH_SIZE];
  	struct ip6_tnl __rcu *tnls_wc[1];
  	struct ip6_tnl __rcu **tnls[2];
13eeb8e92   Pavel Emelyanov   [IP6TUNNEL]: Intr...
99
  };
8560f2266   Eric Dumazet   ip6tnl: percpu st...
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
  static struct net_device_stats *ip6_get_stats(struct net_device *dev)
  {
  	struct pcpu_tstats sum = { 0 };
  	int i;
  
  	for_each_possible_cpu(i) {
  		const struct pcpu_tstats *tstats = per_cpu_ptr(dev->tstats, i);
  
  		sum.rx_packets += tstats->rx_packets;
  		sum.rx_bytes   += tstats->rx_bytes;
  		sum.tx_packets += tstats->tx_packets;
  		sum.tx_bytes   += tstats->tx_bytes;
  	}
  	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;
  }
2922bc8ae   Eric Dumazet   ip6tnl: convert h...
119
  /*
947676326   Eric Dumazet   ip6tnl: get rid o...
120
   * Locking : hash tables are protected by RCU and RTNL
2922bc8ae   Eric Dumazet   ip6tnl: convert h...
121
   */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
122

c12b395a4   xeb@mail.ru   gre: Support GRE ...
123
  struct dst_entry *ip6_tnl_dst_check(struct ip6_tnl *t)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
124
125
  {
  	struct dst_entry *dst = t->dst_cache;
1ab1457c4   YOSHIFUJI Hideaki   [NET] IPV6: Fix w...
126
  	if (dst && dst->obsolete &&
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
127
128
129
130
131
132
133
134
  	    dst->ops->check(dst, t->dst_cookie) == NULL) {
  		t->dst_cache = NULL;
  		dst_release(dst);
  		return NULL;
  	}
  
  	return dst;
  }
c12b395a4   xeb@mail.ru   gre: Support GRE ...
135
  EXPORT_SYMBOL_GPL(ip6_tnl_dst_check);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
136

c12b395a4   xeb@mail.ru   gre: Support GRE ...
137
  void ip6_tnl_dst_reset(struct ip6_tnl *t)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
138
139
140
141
  {
  	dst_release(t->dst_cache);
  	t->dst_cache = NULL;
  }
c12b395a4   xeb@mail.ru   gre: Support GRE ...
142
  EXPORT_SYMBOL_GPL(ip6_tnl_dst_reset);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
143

c12b395a4   xeb@mail.ru   gre: Support GRE ...
144
  void ip6_tnl_dst_store(struct ip6_tnl *t, struct dst_entry *dst)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
145
146
147
148
149
150
  {
  	struct rt6_info *rt = (struct rt6_info *) dst;
  	t->dst_cookie = rt->rt6i_node ? rt->rt6i_node->fn_sernum : 0;
  	dst_release(t->dst_cache);
  	t->dst_cache = dst;
  }
c12b395a4   xeb@mail.ru   gre: Support GRE ...
151
  EXPORT_SYMBOL_GPL(ip6_tnl_dst_store);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
152
153
  
  /**
3144581cb   Yasuyuki Kozakai   [IPV6] IP6TUNNEL:...
154
   * ip6_tnl_lookup - fetch tunnel matching the end-point addresses
1ab1457c4   YOSHIFUJI Hideaki   [NET] IPV6: Fix w...
155
156
   *   @remote: the address of the tunnel exit-point
   *   @local: the address of the tunnel entry-point
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
157
   *
1ab1457c4   YOSHIFUJI Hideaki   [NET] IPV6: Fix w...
158
   * Return:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
159
   *   tunnel matching given end-points if found,
1ab1457c4   YOSHIFUJI Hideaki   [NET] IPV6: Fix w...
160
   *   else fallback tunnel if its device is up,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
161
162
   *   else %NULL
   **/
2922bc8ae   Eric Dumazet   ip6tnl: convert h...
163
164
  #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
165
  static struct ip6_tnl *
b71d1d426   Eric Dumazet   inet: constify ip...
166
  ip6_tnl_lookup(struct net *net, const struct in6_addr *remote, const struct in6_addr *local)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
167
  {
ddbe50320   Eric Dumazet   ipv6: add ipv6_ad...
168
  	unsigned int hash = HASH(remote, local);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
169
  	struct ip6_tnl *t;
3e6c9fb5f   Pavel Emelyanov   [IP6TUNNEL]: Make...
170
  	struct ip6_tnl_net *ip6n = net_generic(net, ip6_tnl_net_id);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
171

ddbe50320   Eric Dumazet   ipv6: add ipv6_ad...
172
  	for_each_ip6_tunnel_rcu(ip6n->tnls_r_l[hash]) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
173
174
175
176
177
  		if (ipv6_addr_equal(local, &t->parms.laddr) &&
  		    ipv6_addr_equal(remote, &t->parms.raddr) &&
  		    (t->dev->flags & IFF_UP))
  			return t;
  	}
2922bc8ae   Eric Dumazet   ip6tnl: convert h...
178
179
  	t = rcu_dereference(ip6n->tnls_wc[0]);
  	if (t && (t->dev->flags & IFF_UP))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
180
181
182
183
184
185
  		return t;
  
  	return NULL;
  }
  
  /**
3144581cb   Yasuyuki Kozakai   [IPV6] IP6TUNNEL:...
186
   * ip6_tnl_bucket - get head of list matching given tunnel parameters
1ab1457c4   YOSHIFUJI Hideaki   [NET] IPV6: Fix w...
187
   *   @p: parameters containing tunnel end-points
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
188
189
   *
   * Description:
3144581cb   Yasuyuki Kozakai   [IPV6] IP6TUNNEL:...
190
   *   ip6_tnl_bucket() returns the head of the list matching the
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
191
192
   *   &struct in6_addr entries laddr and raddr in @p.
   *
1ab1457c4   YOSHIFUJI Hideaki   [NET] IPV6: Fix w...
193
   * Return: head of IPv6 tunnel list
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
194
   **/
947676326   Eric Dumazet   ip6tnl: get rid o...
195
  static struct ip6_tnl __rcu **
c12b395a4   xeb@mail.ru   gre: Support GRE ...
196
  ip6_tnl_bucket(struct ip6_tnl_net *ip6n, const struct __ip6_tnl_parm *p)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
197
  {
b71d1d426   Eric Dumazet   inet: constify ip...
198
199
  	const struct in6_addr *remote = &p->raddr;
  	const struct in6_addr *local = &p->laddr;
95c961747   Eric Dumazet   net: cleanup unsi...
200
  	unsigned int h = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
201
202
203
204
  	int prio = 0;
  
  	if (!ipv6_addr_any(remote) || !ipv6_addr_any(local)) {
  		prio = 1;
ddbe50320   Eric Dumazet   ipv6: add ipv6_ad...
205
  		h = HASH(remote, local);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
206
  	}
3e6c9fb5f   Pavel Emelyanov   [IP6TUNNEL]: Make...
207
  	return &ip6n->tnls[prio][h];
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
208
209
210
  }
  
  /**
3144581cb   Yasuyuki Kozakai   [IPV6] IP6TUNNEL:...
211
   * ip6_tnl_link - add tunnel to hash table
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
212
213
214
215
   *   @t: tunnel to be added
   **/
  
  static void
2dd02c897   Pavel Emelyanov   [IP6TUNNEL]: Add ...
216
  ip6_tnl_link(struct ip6_tnl_net *ip6n, struct ip6_tnl *t)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
217
  {
947676326   Eric Dumazet   ip6tnl: get rid o...
218
  	struct ip6_tnl __rcu **tp = ip6_tnl_bucket(ip6n, &t->parms);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
219

cf778b00e   Eric Dumazet   net: reintroduce ...
220
221
  	rcu_assign_pointer(t->next , rtnl_dereference(*tp));
  	rcu_assign_pointer(*tp, t);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
222
223
224
  }
  
  /**
3144581cb   Yasuyuki Kozakai   [IPV6] IP6TUNNEL:...
225
   * ip6_tnl_unlink - remove tunnel from hash table
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
226
227
228
229
   *   @t: tunnel to be removed
   **/
  
  static void
2dd02c897   Pavel Emelyanov   [IP6TUNNEL]: Add ...
230
  ip6_tnl_unlink(struct ip6_tnl_net *ip6n, struct ip6_tnl *t)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
231
  {
947676326   Eric Dumazet   ip6tnl: get rid o...
232
233
234
235
236
237
238
  	struct ip6_tnl __rcu **tp;
  	struct ip6_tnl *iter;
  
  	for (tp = ip6_tnl_bucket(ip6n, &t->parms);
  	     (iter = rtnl_dereference(*tp)) != NULL;
  	     tp = &iter->next) {
  		if (t == iter) {
cf778b00e   Eric Dumazet   net: reintroduce ...
239
  			rcu_assign_pointer(*tp, t->next);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
240
241
242
243
  			break;
  		}
  	}
  }
8560f2266   Eric Dumazet   ip6tnl: percpu st...
244
245
246
247
248
  static void ip6_dev_free(struct net_device *dev)
  {
  	free_percpu(dev->tstats);
  	free_netdev(dev);
  }
0b1124572   Nicolas Dichtel   ip6tnl: add suppo...
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
  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);
  	err = ip6_tnl_dev_init(dev);
  	if (err < 0)
  		goto out;
  
  	err = register_netdevice(dev);
  	if (err < 0)
  		goto out;
  
  	strcpy(t->parms.name, dev->name);
  	dev->rtnl_link_ops = &ip6_link_ops;
  
  	dev_hold(dev);
  	ip6_tnl_link(ip6n, t);
  	return 0;
  
  out:
  	return err;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
275
  /**
2c53040f0   Ben Hutchings   net: Fix (nearly-...
276
   * ip6_tnl_create - create a new tunnel
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
277
278
279
280
281
   *   @p: tunnel parameters
   *   @pt: pointer to new tunnel
   *
   * Description:
   *   Create tunnel matching given parameters.
1ab1457c4   YOSHIFUJI Hideaki   [NET] IPV6: Fix w...
282
283
   *
   * Return:
567131a72   Ville Nuorvala   [IPV6]: Fix SIOCC...
284
   *   created tunnel or NULL
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
285
   **/
c12b395a4   xeb@mail.ru   gre: Support GRE ...
286
  static struct ip6_tnl *ip6_tnl_create(struct net *net, struct __ip6_tnl_parm *p)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
287
288
289
290
291
  {
  	struct net_device *dev;
  	struct ip6_tnl *t;
  	char name[IFNAMSIZ];
  	int err;
34cc7ba63   Pavel Emelyanov   [IP_TUNNEL]: Don'...
292
  	if (p->name[0])
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
293
  		strlcpy(name, p->name, IFNAMSIZ);
34cc7ba63   Pavel Emelyanov   [IP_TUNNEL]: Don'...
294
295
  	else
  		sprintf(name, "ip6tnl%%d");
3144581cb   Yasuyuki Kozakai   [IPV6] IP6TUNNEL:...
296
  	dev = alloc_netdev(sizeof (*t), name, ip6_tnl_dev_setup);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
297
  	if (dev == NULL)
567131a72   Ville Nuorvala   [IPV6]: Fix SIOCC...
298
  		goto failed;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
299

554eb2778   Pavel Emelyanov   [IP6TUNNEL]: Allo...
300
  	dev_net_set(dev, net);
2941a4863   Patrick McHardy   [NET]: Convert ne...
301
  	t = netdev_priv(dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
302
  	t->parms = *p;
0b1124572   Nicolas Dichtel   ip6tnl: add suppo...
303
  	err = ip6_tnl_create2(dev);
8560f2266   Eric Dumazet   ip6tnl: percpu st...
304
305
  	if (err < 0)
  		goto failed_free;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
306

567131a72   Ville Nuorvala   [IPV6]: Fix SIOCC...
307
  	return t;
b37d428b2   Pavel Emelyanov   [INET]: Don't cre...
308
309
  
  failed_free:
8560f2266   Eric Dumazet   ip6tnl: percpu st...
310
  	ip6_dev_free(dev);
567131a72   Ville Nuorvala   [IPV6]: Fix SIOCC...
311
312
  failed:
  	return NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
313
314
315
  }
  
  /**
3144581cb   Yasuyuki Kozakai   [IPV6] IP6TUNNEL:...
316
   * ip6_tnl_locate - find or create tunnel matching given parameters
1ab1457c4   YOSHIFUJI Hideaki   [NET] IPV6: Fix w...
317
   *   @p: tunnel parameters
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
318
319
320
   *   @create: != 0 if allowed to create new tunnel if no match found
   *
   * Description:
3144581cb   Yasuyuki Kozakai   [IPV6] IP6TUNNEL:...
321
   *   ip6_tnl_locate() first tries to locate an existing tunnel
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
322
323
324
325
   *   based on @parms. If this is unsuccessful, but @create is set a new
   *   tunnel device is created and registered for use.
   *
   * Return:
567131a72   Ville Nuorvala   [IPV6]: Fix SIOCC...
326
   *   matching tunnel or NULL
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
327
   **/
2dd02c897   Pavel Emelyanov   [IP6TUNNEL]: Add ...
328
  static struct ip6_tnl *ip6_tnl_locate(struct net *net,
c12b395a4   xeb@mail.ru   gre: Support GRE ...
329
  		struct __ip6_tnl_parm *p, int create)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
330
  {
b71d1d426   Eric Dumazet   inet: constify ip...
331
332
  	const struct in6_addr *remote = &p->raddr;
  	const struct in6_addr *local = &p->laddr;
947676326   Eric Dumazet   ip6tnl: get rid o...
333
  	struct ip6_tnl __rcu **tp;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
334
  	struct ip6_tnl *t;
2dd02c897   Pavel Emelyanov   [IP6TUNNEL]: Add ...
335
  	struct ip6_tnl_net *ip6n = net_generic(net, ip6_tnl_net_id);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
336

947676326   Eric Dumazet   ip6tnl: get rid o...
337
338
339
  	for (tp = ip6_tnl_bucket(ip6n, p);
  	     (t = rtnl_dereference(*tp)) != NULL;
  	     tp = &t->next) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
340
  		if (ipv6_addr_equal(local, &t->parms.laddr) &&
567131a72   Ville Nuorvala   [IPV6]: Fix SIOCC...
341
342
  		    ipv6_addr_equal(remote, &t->parms.raddr))
  			return t;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
343
344
  	}
  	if (!create)
567131a72   Ville Nuorvala   [IPV6]: Fix SIOCC...
345
  		return NULL;
2dd02c897   Pavel Emelyanov   [IP6TUNNEL]: Add ...
346
  	return ip6_tnl_create(net, p);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
347
348
349
  }
  
  /**
3144581cb   Yasuyuki Kozakai   [IPV6] IP6TUNNEL:...
350
   * ip6_tnl_dev_uninit - tunnel device uninitializer
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
351
   *   @dev: the device to be destroyed
1ab1457c4   YOSHIFUJI Hideaki   [NET] IPV6: Fix w...
352
   *
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
353
   * Description:
3144581cb   Yasuyuki Kozakai   [IPV6] IP6TUNNEL:...
354
   *   ip6_tnl_dev_uninit() removes tunnel from its list
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
355
356
357
   **/
  
  static void
3144581cb   Yasuyuki Kozakai   [IPV6] IP6TUNNEL:...
358
  ip6_tnl_dev_uninit(struct net_device *dev)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
359
  {
2941a4863   Patrick McHardy   [NET]: Convert ne...
360
  	struct ip6_tnl *t = netdev_priv(dev);
2dd02c897   Pavel Emelyanov   [IP6TUNNEL]: Add ...
361
362
  	struct net *net = dev_net(dev);
  	struct ip6_tnl_net *ip6n = net_generic(net, ip6_tnl_net_id);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
363

947676326   Eric Dumazet   ip6tnl: get rid o...
364
  	if (dev == ip6n->fb_tnl_dev)
a9b3cd7f3   Stephen Hemminger   rcu: convert uses...
365
  		RCU_INIT_POINTER(ip6n->tnls_wc[0], NULL);
947676326   Eric Dumazet   ip6tnl: get rid o...
366
  	else
2dd02c897   Pavel Emelyanov   [IP6TUNNEL]: Add ...
367
  		ip6_tnl_unlink(ip6n, t);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
368
369
370
371
372
373
374
375
  	ip6_tnl_dst_reset(t);
  	dev_put(dev);
  }
  
  /**
   * parse_tvl_tnl_enc_lim - handle encapsulation limit option
   *   @skb: received socket buffer
   *
1ab1457c4   YOSHIFUJI Hideaki   [NET] IPV6: Fix w...
376
377
   * Return:
   *   0 if none was found,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
378
379
   *   else index to encapsulation limit
   **/
c12b395a4   xeb@mail.ru   gre: Support GRE ...
380
  __u16 ip6_tnl_parse_tlv_enc_lim(struct sk_buff *skb, __u8 *raw)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
381
  {
b71d1d426   Eric Dumazet   inet: constify ip...
382
  	const struct ipv6hdr *ipv6h = (const struct ipv6hdr *) raw;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
  	__u8 nexthdr = ipv6h->nexthdr;
  	__u16 off = sizeof (*ipv6h);
  
  	while (ipv6_ext_hdr(nexthdr) && nexthdr != NEXTHDR_NONE) {
  		__u16 optlen = 0;
  		struct ipv6_opt_hdr *hdr;
  		if (raw + off + sizeof (*hdr) > skb->data &&
  		    !pskb_may_pull(skb, raw - skb->data + off + sizeof (*hdr)))
  			break;
  
  		hdr = (struct ipv6_opt_hdr *) (raw + off);
  		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) {
  			optlen = (hdr->hdrlen + 2) << 2;
  		} else {
  			optlen = ipv6_optlen(hdr);
  		}
  		if (nexthdr == NEXTHDR_DEST) {
  			__u16 i = off + 2;
  			while (1) {
  				struct ipv6_tlv_tnl_enc_lim *tel;
  
  				/* No more room for encapsulation limit */
  				if (i + sizeof (*tel) > off + optlen)
  					break;
  
  				tel = (struct ipv6_tlv_tnl_enc_lim *) &raw[i];
  				/* return index of option if found and valid */
  				if (tel->type == IPV6_TLV_TNL_ENCAP_LIMIT &&
  				    tel->length == 1)
  					return i;
  				/* else jump to next option */
  				if (tel->type)
  					i += tel->length + 2;
  				else
  					i++;
  			}
  		}
  		nexthdr = hdr->nexthdr;
  		off += optlen;
  	}
  	return 0;
  }
c12b395a4   xeb@mail.ru   gre: Support GRE ...
430
  EXPORT_SYMBOL(ip6_tnl_parse_tlv_enc_lim);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
431
432
  
  /**
e490d1d85   Yasuyuki Kozakai   [IPV6] IP6TUNNEL:...
433
   * ip6_tnl_err - tunnel error handler
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
434
435
   *
   * Description:
e490d1d85   Yasuyuki Kozakai   [IPV6] IP6TUNNEL:...
436
   *   ip6_tnl_err() should handle errors in the tunnel according
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
437
438
   *   to the specifications in RFC 2473.
   **/
d2acc3479   Herbert Xu   [INET]: Introduce...
439
  static int
502b09356   Yasuyuki Kozakai   [IPV6] IP6TUNNEL:...
440
  ip6_tnl_err(struct sk_buff *skb, __u8 ipproto, struct inet6_skb_parm *opt,
d5fdd6bab   Brian Haley   ipv6: Use correct...
441
  	    u8 *type, u8 *code, int *msg, __u32 *info, int offset)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
442
  {
b71d1d426   Eric Dumazet   inet: constify ip...
443
  	const struct ipv6hdr *ipv6h = (const struct ipv6hdr *) skb->data;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
444
445
  	struct ip6_tnl *t;
  	int rel_msg = 0;
d5fdd6bab   Brian Haley   ipv6: Use correct...
446
447
  	u8 rel_type = ICMPV6_DEST_UNREACH;
  	u8 rel_code = ICMPV6_ADDR_UNREACH;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
448
449
  	__u32 rel_info = 0;
  	__u16 len;
d2acc3479   Herbert Xu   [INET]: Introduce...
450
  	int err = -ENOENT;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
451

1ab1457c4   YOSHIFUJI Hideaki   [NET] IPV6: Fix w...
452
453
  	/* 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
454
  	   processing of the error. */
2922bc8ae   Eric Dumazet   ip6tnl: convert h...
455
  	rcu_read_lock();
8704ca7e9   Pavel Emelyanov   [IP6TUNNEL]: Use ...
456
  	if ((t = ip6_tnl_lookup(dev_net(skb->dev), &ipv6h->daddr,
2dd02c897   Pavel Emelyanov   [IP6TUNNEL]: Add ...
457
  					&ipv6h->saddr)) == NULL)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
458
  		goto out;
502b09356   Yasuyuki Kozakai   [IPV6] IP6TUNNEL:...
459
460
  	if (t->parms.proto != ipproto && t->parms.proto != 0)
  		goto out;
d2acc3479   Herbert Xu   [INET]: Introduce...
461
  	err = 0;
e490d1d85   Yasuyuki Kozakai   [IPV6] IP6TUNNEL:...
462
  	switch (*type) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
463
464
465
466
  		__u32 teli;
  		struct ipv6_tlv_tnl_enc_lim *tel;
  		__u32 mtu;
  	case ICMPV6_DEST_UNREACH:
e87cc4728   Joe Perches   net: Convert net_...
467
468
469
  		net_warn_ratelimited("%s: Path to destination invalid or inactive!
  ",
  				     t->parms.name);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
470
471
472
  		rel_msg = 1;
  		break;
  	case ICMPV6_TIME_EXCEED:
e490d1d85   Yasuyuki Kozakai   [IPV6] IP6TUNNEL:...
473
  		if ((*code) == ICMPV6_EXC_HOPLIMIT) {
e87cc4728   Joe Perches   net: Convert net_...
474
475
476
  			net_warn_ratelimited("%s: Too small hop limit or routing loop in tunnel!
  ",
  					     t->parms.name);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
477
478
479
480
  			rel_msg = 1;
  		}
  		break;
  	case ICMPV6_PARAMPROB:
107a5fe61   Ville Nuorvala   [IPV6]: Improve I...
481
  		teli = 0;
e490d1d85   Yasuyuki Kozakai   [IPV6] IP6TUNNEL:...
482
  		if ((*code) == ICMPV6_HDR_FIELD)
c12b395a4   xeb@mail.ru   gre: Support GRE ...
483
  			teli = ip6_tnl_parse_tlv_enc_lim(skb, skb->data);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
484

704eae1f3   Al Viro   ip6_tunnel - endi...
485
  		if (teli && teli == *info - 2) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
486
487
  			tel = (struct ipv6_tlv_tnl_enc_lim *) &skb->data[teli];
  			if (tel->encap_limit == 0) {
e87cc4728   Joe Perches   net: Convert net_...
488
489
490
  				net_warn_ratelimited("%s: Too small encapsulation limit or routing loop in tunnel!
  ",
  						     t->parms.name);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
491
492
  				rel_msg = 1;
  			}
e87cc4728   Joe Perches   net: Convert net_...
493
494
495
496
  		} else {
  			net_warn_ratelimited("%s: Recipient unable to parse tunneled packet!
  ",
  					     t->parms.name);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
497
498
499
  		}
  		break;
  	case ICMPV6_PKT_TOOBIG:
704eae1f3   Al Viro   ip6_tunnel - endi...
500
  		mtu = *info - offset;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
501
502
503
  		if (mtu < IPV6_MIN_MTU)
  			mtu = IPV6_MIN_MTU;
  		t->dev->mtu = mtu;
cc6cdac0c   Al Viro   [PATCH] missing n...
504
  		if ((len = sizeof (*ipv6h) + ntohs(ipv6h->payload_len)) > mtu) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
505
506
507
508
509
510
511
  			rel_type = ICMPV6_PKT_TOOBIG;
  			rel_code = 0;
  			rel_info = mtu;
  			rel_msg = 1;
  		}
  		break;
  	}
e490d1d85   Yasuyuki Kozakai   [IPV6] IP6TUNNEL:...
512
513
514
515
516
517
518
  
  	*type = rel_type;
  	*code = rel_code;
  	*info = rel_info;
  	*msg = rel_msg;
  
  out:
2922bc8ae   Eric Dumazet   ip6tnl: convert h...
519
  	rcu_read_unlock();
e490d1d85   Yasuyuki Kozakai   [IPV6] IP6TUNNEL:...
520
521
522
523
  	return err;
  }
  
  static int
c4d3efafc   Yasuyuki Kozakai   [IPV6] IP6TUNNEL:...
524
  ip4ip6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
d5fdd6bab   Brian Haley   ipv6: Use correct...
525
  	   u8 type, u8 code, int offset, __be32 info)
c4d3efafc   Yasuyuki Kozakai   [IPV6] IP6TUNNEL:...
526
527
  {
  	int rel_msg = 0;
d5fdd6bab   Brian Haley   ipv6: Use correct...
528
529
  	u8 rel_type = type;
  	u8 rel_code = code;
704eae1f3   Al Viro   ip6_tunnel - endi...
530
  	__u32 rel_info = ntohl(info);
c4d3efafc   Yasuyuki Kozakai   [IPV6] IP6TUNNEL:...
531
532
  	int err;
  	struct sk_buff *skb2;
b71d1d426   Eric Dumazet   inet: constify ip...
533
  	const struct iphdr *eiph;
c4d3efafc   Yasuyuki Kozakai   [IPV6] IP6TUNNEL:...
534
  	struct rtable *rt;
31e4543db   David S. Miller   ipv4: Make caller...
535
  	struct flowi4 fl4;
c4d3efafc   Yasuyuki Kozakai   [IPV6] IP6TUNNEL:...
536

502b09356   Yasuyuki Kozakai   [IPV6] IP6TUNNEL:...
537
538
  	err = ip6_tnl_err(skb, IPPROTO_IPIP, opt, &rel_type, &rel_code,
  			  &rel_msg, &rel_info, offset);
c4d3efafc   Yasuyuki Kozakai   [IPV6] IP6TUNNEL:...
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
  	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;
ec18d9a26   David S. Miller   ipv6: Add redirec...
558
559
560
  	case NDISC_REDIRECT:
  		rel_type = ICMP_REDIRECT;
  		rel_code = ICMP_REDIR_HOST;
c4d3efafc   Yasuyuki Kozakai   [IPV6] IP6TUNNEL:...
561
562
563
564
565
566
567
568
569
570
  	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...
571
  	skb_dst_drop(skb2);
c4d3efafc   Yasuyuki Kozakai   [IPV6] IP6TUNNEL:...
572
  	skb_pull(skb2, offset);
c1d2bbe1c   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
573
  	skb_reset_network_header(skb2);
eddc9ec53   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
574
  	eiph = ip_hdr(skb2);
c4d3efafc   Yasuyuki Kozakai   [IPV6] IP6TUNNEL:...
575
576
  
  	/* Try to guess incoming interface */
31e4543db   David S. Miller   ipv4: Make caller...
577
  	rt = ip_route_output_ports(dev_net(skb->dev), &fl4, NULL,
78fbfd8a6   David S. Miller   ipv4: Create and ...
578
579
580
  				   eiph->saddr, 0,
  				   0, 0,
  				   IPPROTO_IPIP, RT_TOS(eiph->tos), 0);
b23dd4fe4   David S. Miller   ipv4: Make output...
581
  	if (IS_ERR(rt))
c4d3efafc   Yasuyuki Kozakai   [IPV6] IP6TUNNEL:...
582
  		goto out;
d8d1f30b9   Changli Gao   net-next: remove ...
583
  	skb2->dev = rt->dst.dev;
c4d3efafc   Yasuyuki Kozakai   [IPV6] IP6TUNNEL:...
584
585
586
587
588
  
  	/* route "incoming" packet */
  	if (rt->rt_flags & RTCF_LOCAL) {
  		ip_rt_put(rt);
  		rt = NULL;
31e4543db   David S. Miller   ipv4: Make caller...
589
  		rt = ip_route_output_ports(dev_net(skb->dev), &fl4, NULL,
78fbfd8a6   David S. Miller   ipv4: Create and ...
590
591
592
593
  					   eiph->daddr, eiph->saddr,
  					   0, 0,
  					   IPPROTO_IPIP,
  					   RT_TOS(eiph->tos), 0);
b23dd4fe4   David S. Miller   ipv4: Make output...
594
  		if (IS_ERR(rt) ||
d8d1f30b9   Changli Gao   net-next: remove ...
595
  		    rt->dst.dev->type != ARPHRD_TUNNEL) {
b23dd4fe4   David S. Miller   ipv4: Make output...
596
597
  			if (!IS_ERR(rt))
  				ip_rt_put(rt);
c4d3efafc   Yasuyuki Kozakai   [IPV6] IP6TUNNEL:...
598
599
  			goto out;
  		}
b23dd4fe4   David S. Miller   ipv4: Make output...
600
  		skb_dst_set(skb2, &rt->dst);
c4d3efafc   Yasuyuki Kozakai   [IPV6] IP6TUNNEL:...
601
602
603
604
  	} else {
  		ip_rt_put(rt);
  		if (ip_route_input(skb2, eiph->daddr, eiph->saddr, eiph->tos,
  				   skb2->dev) ||
adf30907d   Eric Dumazet   net: skb->dst acc...
605
  		    skb_dst(skb2)->dev->type != ARPHRD_TUNNEL)
c4d3efafc   Yasuyuki Kozakai   [IPV6] IP6TUNNEL:...
606
607
608
609
610
  			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...
611
  		if (rel_info > dst_mtu(skb_dst(skb2)))
c4d3efafc   Yasuyuki Kozakai   [IPV6] IP6TUNNEL:...
612
  			goto out;
6700c2709   David S. Miller   net: Pass optiona...
613
  		skb_dst(skb2)->ops->update_pmtu(skb_dst(skb2), NULL, skb2, rel_info);
c4d3efafc   Yasuyuki Kozakai   [IPV6] IP6TUNNEL:...
614
  	}
1ed5c48f2   David S. Miller   net: Remove check...
615
  	if (rel_type == ICMP_REDIRECT)
6700c2709   David S. Miller   net: Pass optiona...
616
  		skb_dst(skb2)->ops->redirect(skb_dst(skb2), NULL, skb2);
c4d3efafc   Yasuyuki Kozakai   [IPV6] IP6TUNNEL:...
617

704eae1f3   Al Viro   ip6_tunnel - endi...
618
  	icmp_send(skb2, rel_type, rel_code, htonl(rel_info));
c4d3efafc   Yasuyuki Kozakai   [IPV6] IP6TUNNEL:...
619
620
621
622
623
624
625
  
  out:
  	kfree_skb(skb2);
  	return 0;
  }
  
  static int
e490d1d85   Yasuyuki Kozakai   [IPV6] IP6TUNNEL:...
626
  ip6ip6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
d5fdd6bab   Brian Haley   ipv6: Use correct...
627
  	   u8 type, u8 code, int offset, __be32 info)
e490d1d85   Yasuyuki Kozakai   [IPV6] IP6TUNNEL:...
628
629
  {
  	int rel_msg = 0;
d5fdd6bab   Brian Haley   ipv6: Use correct...
630
631
  	u8 rel_type = type;
  	u8 rel_code = code;
704eae1f3   Al Viro   ip6_tunnel - endi...
632
  	__u32 rel_info = ntohl(info);
e490d1d85   Yasuyuki Kozakai   [IPV6] IP6TUNNEL:...
633
  	int err;
502b09356   Yasuyuki Kozakai   [IPV6] IP6TUNNEL:...
634
635
  	err = ip6_tnl_err(skb, IPPROTO_IPV6, opt, &rel_type, &rel_code,
  			  &rel_msg, &rel_info, offset);
e490d1d85   Yasuyuki Kozakai   [IPV6] IP6TUNNEL:...
636
637
638
639
  	if (err < 0)
  		return err;
  
  	if (rel_msg && pskb_may_pull(skb, offset + sizeof(struct ipv6hdr))) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
640
641
  		struct rt6_info *rt;
  		struct sk_buff *skb2 = skb_clone(skb, GFP_ATOMIC);
305d4b3ce   Ville Nuorvala   [IPV6]: Allow lin...
642

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

adf30907d   Eric Dumazet   net: skb->dst acc...
646
  		skb_dst_drop(skb2);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
647
  		skb_pull(skb2, offset);
c1d2bbe1c   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
648
  		skb_reset_network_header(skb2);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
649
650
  
  		/* Try to guess incoming interface */
2f7f54b72   Pavel Emelyanov   [IP6TUNNEL]: Use ...
651
652
  		rt = rt6_lookup(dev_net(skb->dev), &ipv6_hdr(skb2)->saddr,
  				NULL, 0, 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
653

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

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

94e187c01   Amerigo Wang   ipv6: introduce i...
659
  		ip6_rt_put(rt);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
660
661
662
  
  		kfree_skb(skb2);
  	}
e490d1d85   Yasuyuki Kozakai   [IPV6] IP6TUNNEL:...
663
664
  
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
665
  }
f4e0b4c5e   Nicolas Dichtel   ip6tnl/sit: drop ...
666
667
668
  static int ip4ip6_dscp_ecn_decapsulate(const struct ip6_tnl *t,
  				       const struct ipv6hdr *ipv6h,
  				       struct sk_buff *skb)
c4d3efafc   Yasuyuki Kozakai   [IPV6] IP6TUNNEL:...
669
670
671
672
  {
  	__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...
673
  		ipv4_change_dsfield(ip_hdr(skb), INET_ECN_MASK, dsfield);
c4d3efafc   Yasuyuki Kozakai   [IPV6] IP6TUNNEL:...
674

f4e0b4c5e   Nicolas Dichtel   ip6tnl/sit: drop ...
675
  	return IP6_ECN_decapsulate(ipv6h, skb);
c4d3efafc   Yasuyuki Kozakai   [IPV6] IP6TUNNEL:...
676
  }
f4e0b4c5e   Nicolas Dichtel   ip6tnl/sit: drop ...
677
678
679
  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
680
  {
8359925be   Yasuyuki Kozakai   [IPV6] IP6TUNNEL:...
681
  	if (t->parms.flags & IP6_TNL_F_RCV_DSCP_COPY)
29bb43b4e   Herbert Xu   [INET]: Give oute...
682
  		ipv6_copy_dscp(ipv6_get_dsfield(ipv6h), ipv6_hdr(skb));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
683

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

c12b395a4   xeb@mail.ru   gre: Support GRE ...
687
  __u32 ip6_tnl_get_cap(struct ip6_tnl *t,
d0087b29f   Ville Nuorvala   ipv6_tunnel: Allo...
688
689
690
  			     const struct in6_addr *laddr,
  			     const struct in6_addr *raddr)
  {
c12b395a4   xeb@mail.ru   gre: Support GRE ...
691
  	struct __ip6_tnl_parm *p = &t->parms;
d0087b29f   Ville Nuorvala   ipv6_tunnel: Allo...
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
  	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 ...
709
  EXPORT_SYMBOL(ip6_tnl_get_cap);
d0087b29f   Ville Nuorvala   ipv6_tunnel: Allo...
710

f1a28eab2   Eric Dumazet   ip6tnl: less dev_...
711
  /* called with rcu_read_lock() */
c12b395a4   xeb@mail.ru   gre: Support GRE ...
712
  int ip6_tnl_rcv_ctl(struct ip6_tnl *t,
d0087b29f   Ville Nuorvala   ipv6_tunnel: Allo...
713
714
  				  const struct in6_addr *laddr,
  				  const struct in6_addr *raddr)
09c6bbf09   Ville Nuorvala   [IPV6]: Do mandat...
715
  {
c12b395a4   xeb@mail.ru   gre: Support GRE ...
716
  	struct __ip6_tnl_parm *p = &t->parms;
09c6bbf09   Ville Nuorvala   [IPV6]: Do mandat...
717
  	int ret = 0;
2f7f54b72   Pavel Emelyanov   [IP6TUNNEL]: Use ...
718
  	struct net *net = dev_net(t->dev);
09c6bbf09   Ville Nuorvala   [IPV6]: Do mandat...
719

d0087b29f   Ville Nuorvala   ipv6_tunnel: Allo...
720
721
722
  	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...
723
  		struct net_device *ldev = NULL;
09c6bbf09   Ville Nuorvala   [IPV6]: Do mandat...
724
725
  
  		if (p->link)
f1a28eab2   Eric Dumazet   ip6tnl: less dev_...
726
  			ldev = dev_get_by_index_rcu(net, p->link);
09c6bbf09   Ville Nuorvala   [IPV6]: Do mandat...
727

d0087b29f   Ville Nuorvala   ipv6_tunnel: Allo...
728
729
730
  		if ((ipv6_addr_is_multicast(laddr) ||
  		     likely(ipv6_chk_addr(net, laddr, ldev, 0))) &&
  		    likely(!ipv6_chk_addr(net, raddr, NULL, 0)))
09c6bbf09   Ville Nuorvala   [IPV6]: Do mandat...
731
  			ret = 1;
09c6bbf09   Ville Nuorvala   [IPV6]: Do mandat...
732
733
734
  	}
  	return ret;
  }
c12b395a4   xeb@mail.ru   gre: Support GRE ...
735
  EXPORT_SYMBOL_GPL(ip6_tnl_rcv_ctl);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
736
737
  
  /**
3144581cb   Yasuyuki Kozakai   [IPV6] IP6TUNNEL:...
738
   * ip6_tnl_rcv - decapsulate IPv6 packet and retransmit it locally
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
739
   *   @skb: received socket buffer
8359925be   Yasuyuki Kozakai   [IPV6] IP6TUNNEL:...
740
741
   *   @protocol: ethernet protocol ID
   *   @dscp_ecn_decapsulate: the function to decapsulate DSCP code and ECN
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
742
743
744
   *
   * Return: 0
   **/
8359925be   Yasuyuki Kozakai   [IPV6] IP6TUNNEL:...
745
  static int ip6_tnl_rcv(struct sk_buff *skb, __u16 protocol,
502b09356   Yasuyuki Kozakai   [IPV6] IP6TUNNEL:...
746
  		       __u8 ipproto,
f4e0b4c5e   Nicolas Dichtel   ip6tnl/sit: drop ...
747
748
749
  		       int (*dscp_ecn_decapsulate)(const struct ip6_tnl *t,
  						   const struct ipv6hdr *ipv6h,
  						   struct sk_buff *skb))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
750
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
751
  	struct ip6_tnl *t;
b71d1d426   Eric Dumazet   inet: constify ip...
752
  	const struct ipv6hdr *ipv6h = ipv6_hdr(skb);
f4e0b4c5e   Nicolas Dichtel   ip6tnl/sit: drop ...
753
  	int err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
754

2922bc8ae   Eric Dumazet   ip6tnl: convert h...
755
  	rcu_read_lock();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
756

8704ca7e9   Pavel Emelyanov   [IP6TUNNEL]: Use ...
757
  	if ((t = ip6_tnl_lookup(dev_net(skb->dev), &ipv6h->saddr,
2dd02c897   Pavel Emelyanov   [IP6TUNNEL]: Add ...
758
  					&ipv6h->daddr)) != NULL) {
8560f2266   Eric Dumazet   ip6tnl: percpu st...
759
  		struct pcpu_tstats *tstats;
502b09356   Yasuyuki Kozakai   [IPV6] IP6TUNNEL:...
760
  		if (t->parms.proto != ipproto && t->parms.proto != 0) {
2922bc8ae   Eric Dumazet   ip6tnl: convert h...
761
  			rcu_read_unlock();
502b09356   Yasuyuki Kozakai   [IPV6] IP6TUNNEL:...
762
763
  			goto discard;
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
764
  		if (!xfrm6_policy_check(NULL, XFRM_POLICY_IN, skb)) {
2922bc8ae   Eric Dumazet   ip6tnl: convert h...
765
  			rcu_read_unlock();
50fba2aa7   Herbert Xu   [INET]: Move no-t...
766
  			goto discard;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
767
  		}
d0087b29f   Ville Nuorvala   ipv6_tunnel: Allo...
768
  		if (!ip6_tnl_rcv_ctl(t, &ipv6h->daddr, &ipv6h->saddr)) {
3dca02af3   Pavel Emelyanov   ip6tnl: Use on-de...
769
  			t->dev->stats.rx_dropped++;
2922bc8ae   Eric Dumazet   ip6tnl: convert h...
770
  			rcu_read_unlock();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
771
772
773
  			goto discard;
  		}
  		secpath_reset(skb);
b0e380b1d   Arnaldo Carvalho de Melo   [SK_BUFF]: unions...
774
  		skb->mac_header = skb->network_header;
c1d2bbe1c   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
775
  		skb_reset_network_header(skb);
8359925be   Yasuyuki Kozakai   [IPV6] IP6TUNNEL:...
776
  		skb->protocol = htons(protocol);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
777
778
  		skb->pkt_type = PACKET_HOST;
  		memset(skb->cb, 0, sizeof(struct inet6_skb_parm));
8359925be   Yasuyuki Kozakai   [IPV6] IP6TUNNEL:...
779

f4e0b4c5e   Nicolas Dichtel   ip6tnl/sit: drop ...
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
  		__skb_tunnel_rx(skb, t->dev);
  
  		err = dscp_ecn_decapsulate(t, ipv6h, skb);
  		if (unlikely(err)) {
  			if (log_ecn_error)
  				net_info_ratelimited("non-ECT from %pI6 with dsfield=%#x
  ",
  						     &ipv6h->saddr,
  						     ipv6_get_dsfield(ipv6h));
  			if (err > 1) {
  				++t->dev->stats.rx_frame_errors;
  				++t->dev->stats.rx_errors;
  				rcu_read_unlock();
  				goto discard;
  			}
  		}
8560f2266   Eric Dumazet   ip6tnl: percpu st...
796
797
798
  		tstats = this_cpu_ptr(t->dev->tstats);
  		tstats->rx_packets++;
  		tstats->rx_bytes += skb->len;
caf586e5f   Eric Dumazet   net: add a core n...
799
  		netif_rx(skb);
8990f468a   Eric Dumazet   net: rx_dropped a...
800

2922bc8ae   Eric Dumazet   ip6tnl: convert h...
801
  		rcu_read_unlock();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
802
803
  		return 0;
  	}
2922bc8ae   Eric Dumazet   ip6tnl: convert h...
804
  	rcu_read_unlock();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
805
  	return 1;
50fba2aa7   Herbert Xu   [INET]: Move no-t...
806
807
808
809
  
  discard:
  	kfree_skb(skb);
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
810
  }
c4d3efafc   Yasuyuki Kozakai   [IPV6] IP6TUNNEL:...
811
812
  static int ip4ip6_rcv(struct sk_buff *skb)
  {
502b09356   Yasuyuki Kozakai   [IPV6] IP6TUNNEL:...
813
814
  	return ip6_tnl_rcv(skb, ETH_P_IP, IPPROTO_IPIP,
  			   ip4ip6_dscp_ecn_decapsulate);
c4d3efafc   Yasuyuki Kozakai   [IPV6] IP6TUNNEL:...
815
  }
8359925be   Yasuyuki Kozakai   [IPV6] IP6TUNNEL:...
816
817
  static int ip6ip6_rcv(struct sk_buff *skb)
  {
502b09356   Yasuyuki Kozakai   [IPV6] IP6TUNNEL:...
818
819
  	return ip6_tnl_rcv(skb, ETH_P_IPV6, IPPROTO_IPV6,
  			   ip6ip6_dscp_ecn_decapsulate);
8359925be   Yasuyuki Kozakai   [IPV6] IP6TUNNEL:...
820
  }
6fb32ddeb   Ville Nuorvala   [IPV6]: Don't all...
821
822
823
824
  struct ipv6_tel_txoption {
  	struct ipv6_txoptions ops;
  	__u8 dst_opt[8];
  };
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
825

6fb32ddeb   Ville Nuorvala   [IPV6]: Don't all...
826
827
828
  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
829

6fb32ddeb   Ville Nuorvala   [IPV6]: Don't all...
830
831
832
833
834
  	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
835

6fb32ddeb   Ville Nuorvala   [IPV6]: Don't all...
836
837
  	opt->ops.dst0opt = (struct ipv6_opt_hdr *) opt->dst_opt;
  	opt->ops.opt_nflen = 8;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
838
839
840
  }
  
  /**
3144581cb   Yasuyuki Kozakai   [IPV6] IP6TUNNEL:...
841
   * ip6_tnl_addr_conflict - compare packet addresses to tunnel's own
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
842
   *   @t: the outgoing tunnel device
1ab1457c4   YOSHIFUJI Hideaki   [NET] IPV6: Fix w...
843
   *   @hdr: IPv6 header from the incoming packet
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
844
845
   *
   * Description:
1ab1457c4   YOSHIFUJI Hideaki   [NET] IPV6: Fix w...
846
   *   Avoid trivial tunneling loop by checking that tunnel exit-point
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
847
848
   *   doesn't match source of incoming packet.
   *
1ab1457c4   YOSHIFUJI Hideaki   [NET] IPV6: Fix w...
849
   * Return:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
850
851
852
   *   1 if conflict,
   *   0 else
   **/
92113bfde   Eric Dumazet   ipv6: bool conver...
853
  static inline bool
b71d1d426   Eric Dumazet   inet: constify ip...
854
  ip6_tnl_addr_conflict(const struct ip6_tnl *t, const struct ipv6hdr *hdr)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
855
856
857
  {
  	return ipv6_addr_equal(&t->parms.raddr, &hdr->saddr);
  }
c12b395a4   xeb@mail.ru   gre: Support GRE ...
858
  int ip6_tnl_xmit_ctl(struct ip6_tnl *t)
09c6bbf09   Ville Nuorvala   [IPV6]: Do mandat...
859
  {
c12b395a4   xeb@mail.ru   gre: Support GRE ...
860
  	struct __ip6_tnl_parm *p = &t->parms;
09c6bbf09   Ville Nuorvala   [IPV6]: Do mandat...
861
  	int ret = 0;
2f7f54b72   Pavel Emelyanov   [IP6TUNNEL]: Use ...
862
  	struct net *net = dev_net(t->dev);
09c6bbf09   Ville Nuorvala   [IPV6]: Do mandat...
863

1ab1457c4   YOSHIFUJI Hideaki   [NET] IPV6: Fix w...
864
  	if (p->flags & IP6_TNL_F_CAP_XMIT) {
09c6bbf09   Ville Nuorvala   [IPV6]: Do mandat...
865
  		struct net_device *ldev = NULL;
f1a28eab2   Eric Dumazet   ip6tnl: less dev_...
866
  		rcu_read_lock();
09c6bbf09   Ville Nuorvala   [IPV6]: Do mandat...
867
  		if (p->link)
f1a28eab2   Eric Dumazet   ip6tnl: less dev_...
868
  			ldev = dev_get_by_index_rcu(net, p->link);
09c6bbf09   Ville Nuorvala   [IPV6]: Do mandat...
869

2f7f54b72   Pavel Emelyanov   [IP6TUNNEL]: Use ...
870
  		if (unlikely(!ipv6_chk_addr(net, &p->laddr, ldev, 0)))
f32138319   Joe Perches   net: ipv6: Standa...
871
872
873
  			pr_warn("%s xmit: Local address not yet configured!
  ",
  				p->name);
09c6bbf09   Ville Nuorvala   [IPV6]: Do mandat...
874
  		else if (!ipv6_addr_is_multicast(&p->raddr) &&
2f7f54b72   Pavel Emelyanov   [IP6TUNNEL]: Use ...
875
  			 unlikely(ipv6_chk_addr(net, &p->raddr, NULL, 0)))
f32138319   Joe Perches   net: ipv6: Standa...
876
877
878
  			pr_warn("%s xmit: Routing loop! Remote address found on this node!
  ",
  				p->name);
09c6bbf09   Ville Nuorvala   [IPV6]: Do mandat...
879
880
  		else
  			ret = 1;
f1a28eab2   Eric Dumazet   ip6tnl: less dev_...
881
  		rcu_read_unlock();
09c6bbf09   Ville Nuorvala   [IPV6]: Do mandat...
882
883
884
  	}
  	return ret;
  }
c12b395a4   xeb@mail.ru   gre: Support GRE ...
885
  EXPORT_SYMBOL_GPL(ip6_tnl_xmit_ctl);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
886
  /**
61ec2aec2   Yasuyuki Kozakai   [IPV6] IP6TUNNEL:...
887
   * ip6_tnl_xmit2 - encapsulate packet and send
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
888
   *   @skb: the outgoing socket buffer
1ab1457c4   YOSHIFUJI Hideaki   [NET] IPV6: Fix w...
889
   *   @dev: the outgoing tunnel device
61ec2aec2   Yasuyuki Kozakai   [IPV6] IP6TUNNEL:...
890
891
892
893
   *   @dsfield: dscp code for outer header
   *   @fl: flow of tunneled packet
   *   @encap_limit: encapsulation limit
   *   @pmtu: Path MTU is stored if packet is too big
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
894
895
896
897
898
   *
   * Description:
   *   Build new header and do some sanity checks on the packet before sending
   *   it.
   *
1ab1457c4   YOSHIFUJI Hideaki   [NET] IPV6: Fix w...
899
   * Return:
c4d3efafc   Yasuyuki Kozakai   [IPV6] IP6TUNNEL:...
900
   *   0 on success
61ec2aec2   Yasuyuki Kozakai   [IPV6] IP6TUNNEL:...
901
902
   *   -1 fail
   *   %-EMSGSIZE message too big. return mtu in this case.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
903
   **/
61ec2aec2   Yasuyuki Kozakai   [IPV6] IP6TUNNEL:...
904
905
906
  static int ip6_tnl_xmit2(struct sk_buff *skb,
  			 struct net_device *dev,
  			 __u8 dsfield,
4c9483b2f   David S. Miller   ipv6: Convert to ...
907
  			 struct flowi6 *fl6,
61ec2aec2   Yasuyuki Kozakai   [IPV6] IP6TUNNEL:...
908
909
  			 int encap_limit,
  			 __u32 *pmtu)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
910
  {
52479b623   Alexey Dobriyan   netns xfrm: looku...
911
  	struct net *net = dev_net(dev);
2941a4863   Patrick McHardy   [NET]: Convert ne...
912
  	struct ip6_tnl *t = netdev_priv(dev);
3dca02af3   Pavel Emelyanov   ip6tnl: Use on-de...
913
  	struct net_device_stats *stats = &t->dev->stats;
0660e03f6   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
914
  	struct ipv6hdr *ipv6h = ipv6_hdr(skb);
6fb32ddeb   Ville Nuorvala   [IPV6]: Don't all...
915
  	struct ipv6_tel_txoption opt;
d24f22f3d   Eric Dumazet   ip6_tunnel: add o...
916
  	struct dst_entry *dst = NULL, *ndst = NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
917
918
  	struct net_device *tdev;
  	int mtu;
c2636b4d9   Chuck Lever   [NET]: Treat the ...
919
  	unsigned int max_headroom = sizeof(struct ipv6hdr);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
920
  	u8 proto;
61ec2aec2   Yasuyuki Kozakai   [IPV6] IP6TUNNEL:...
921
  	int err = -1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
922

d24f22f3d   Eric Dumazet   ip6_tunnel: add o...
923
924
  	if (!fl6->flowi6_mark)
  		dst = ip6_tnl_dst_check(t);
89b021269   Eric Dumazet   ip6tnl: avoid tou...
925
926
  	if (!dst) {
  		ndst = ip6_route_output(net, NULL, fl6);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
927

89b021269   Eric Dumazet   ip6tnl: avoid tou...
928
  		if (ndst->error)
a57ebc90f   Patrick McHardy   [IPV6]: Don't red...
929
  			goto tx_err_link_failure;
89b021269   Eric Dumazet   ip6tnl: avoid tou...
930
931
932
933
  		ndst = xfrm_lookup(net, ndst, flowi6_to_flowi(fl6), NULL, 0);
  		if (IS_ERR(ndst)) {
  			err = PTR_ERR(ndst);
  			ndst = NULL;
452edd598   David S. Miller   xfrm: Return dst ...
934
935
  			goto tx_err_link_failure;
  		}
89b021269   Eric Dumazet   ip6tnl: avoid tou...
936
  		dst = ndst;
a57ebc90f   Patrick McHardy   [IPV6]: Don't red...
937
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
938
939
940
941
942
  
  	tdev = dst->dev;
  
  	if (tdev == dev) {
  		stats->collisions++;
e87cc4728   Joe Perches   net: Convert net_...
943
944
945
  		net_warn_ratelimited("%s: Local routing loop detected!
  ",
  				     t->parms.name);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
946
947
948
  		goto tx_err_dst_release;
  	}
  	mtu = dst_mtu(dst) - sizeof (*ipv6h);
6fb32ddeb   Ville Nuorvala   [IPV6]: Don't all...
949
  	if (encap_limit >= 0) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
950
951
952
953
954
  		max_headroom += 8;
  		mtu -= 8;
  	}
  	if (mtu < IPV6_MIN_MTU)
  		mtu = IPV6_MIN_MTU;
adf30907d   Eric Dumazet   net: skb->dst acc...
955
  	if (skb_dst(skb))
6700c2709   David S. Miller   net: Pass optiona...
956
  		skb_dst(skb)->ops->update_pmtu(skb_dst(skb), NULL, skb, mtu);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
957
  	if (skb->len > mtu) {
61ec2aec2   Yasuyuki Kozakai   [IPV6] IP6TUNNEL:...
958
959
  		*pmtu = mtu;
  		err = -EMSGSIZE;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
960
961
962
963
964
965
966
  		goto tx_err_dst_release;
  	}
  
  	/*
  	 * 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...
967

cfbba49d8   Patrick McHardy   [NET]: Avoid copy...
968
969
  	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
970
  		struct sk_buff *new_skb;
1ab1457c4   YOSHIFUJI Hideaki   [NET] IPV6: Fix w...
971

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
972
973
974
975
976
  		if (!(new_skb = skb_realloc_headroom(skb, max_headroom)))
  			goto tx_err_dst_release;
  
  		if (skb->sk)
  			skb_set_owner_w(new_skb, skb->sk);
9ff264492   Eric Dumazet   ip6_tunnel: dont ...
977
  		consume_skb(skb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
978
979
  		skb = new_skb;
  	}
adf30907d   Eric Dumazet   net: skb->dst acc...
980
  	skb_dst_drop(skb);
d24f22f3d   Eric Dumazet   ip6_tunnel: add o...
981
982
983
984
985
986
  	if (fl6->flowi6_mark) {
  		skb_dst_set(skb, dst);
  		ndst = NULL;
  	} else {
  		skb_dst_set_noref(skb, dst);
  	}
b0e380b1d   Arnaldo Carvalho de Melo   [SK_BUFF]: unions...
987
  	skb->transport_header = skb->network_header;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
988

4c9483b2f   David S. Miller   ipv6: Convert to ...
989
  	proto = fl6->flowi6_proto;
6fb32ddeb   Ville Nuorvala   [IPV6]: Don't all...
990
991
992
993
  	if (encap_limit >= 0) {
  		init_tel_txopt(&opt, encap_limit);
  		ipv6_push_nfrag_opts(skb, &opt.ops, &proto, NULL);
  	}
e2d1bca7e   Arnaldo Carvalho de Melo   [SK_BUFF]: Use sk...
994
995
  	skb_push(skb, sizeof(struct ipv6hdr));
  	skb_reset_network_header(skb);
0660e03f6   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
996
  	ipv6h = ipv6_hdr(skb);
3e4e4c1f2   YOSHIFUJI Hideaki / 吉藤英明   ipv6: Introduce i...
997
  	ip6_flow_hdr(ipv6h, INET_ECN_encapsulate(0, dsfield), fl6->flowlabel);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
998
999
  	ipv6h->hop_limit = t->parms.hop_limit;
  	ipv6h->nexthdr = proto;
4e3fd7a06   Alexey Dobriyan   net: remove ipv6_...
1000
1001
  	ipv6h->saddr = fl6->saddr;
  	ipv6h->daddr = fl6->daddr;
e8f72ea4a   Cong Wang   ipv6: introduce i...
1002
  	ip6tunnel_xmit(skb, dev);
89b021269   Eric Dumazet   ip6tnl: avoid tou...
1003
1004
  	if (ndst)
  		ip6_tnl_dst_store(t, ndst);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1005
1006
1007
1008
1009
  	return 0;
  tx_err_link_failure:
  	stats->tx_carrier_errors++;
  	dst_link_failure(skb);
  tx_err_dst_release:
89b021269   Eric Dumazet   ip6tnl: avoid tou...
1010
  	dst_release(ndst);
61ec2aec2   Yasuyuki Kozakai   [IPV6] IP6TUNNEL:...
1011
1012
1013
1014
  	return err;
  }
  
  static inline int
c4d3efafc   Yasuyuki Kozakai   [IPV6] IP6TUNNEL:...
1015
1016
1017
  ip4ip6_tnl_xmit(struct sk_buff *skb, struct net_device *dev)
  {
  	struct ip6_tnl *t = netdev_priv(dev);
b71d1d426   Eric Dumazet   inet: constify ip...
1018
  	const struct iphdr  *iph = ip_hdr(skb);
c4d3efafc   Yasuyuki Kozakai   [IPV6] IP6TUNNEL:...
1019
  	int encap_limit = -1;
4c9483b2f   David S. Miller   ipv6: Convert to ...
1020
  	struct flowi6 fl6;
c4d3efafc   Yasuyuki Kozakai   [IPV6] IP6TUNNEL:...
1021
1022
1023
  	__u8 dsfield;
  	__u32 mtu;
  	int err;
502b09356   Yasuyuki Kozakai   [IPV6] IP6TUNNEL:...
1024
1025
  	if ((t->parms.proto != IPPROTO_IPIP && t->parms.proto != 0) ||
  	    !ip6_tnl_xmit_ctl(t))
c4d3efafc   Yasuyuki Kozakai   [IPV6] IP6TUNNEL:...
1026
1027
1028
1029
  		return -1;
  
  	if (!(t->parms.flags & IP6_TNL_F_IGN_ENCAP_LIMIT))
  		encap_limit = t->parms.encap_limit;
4c9483b2f   David S. Miller   ipv6: Convert to ...
1030
1031
  	memcpy(&fl6, &t->fl.u.ip6, sizeof (fl6));
  	fl6.flowi6_proto = IPPROTO_IPIP;
c4d3efafc   Yasuyuki Kozakai   [IPV6] IP6TUNNEL:...
1032
1033
  
  	dsfield = ipv4_get_dsfield(iph);
d24f22f3d   Eric Dumazet   ip6_tunnel: add o...
1034
  	if (t->parms.flags & IP6_TNL_F_USE_ORIG_TCLASS)
4c9483b2f   David S. Miller   ipv6: Convert to ...
1035
  		fl6.flowlabel |= htonl((__u32)iph->tos << IPV6_TCLASS_SHIFT)
b77f2fa62   Al Viro   [IPV6]: endiannes...
1036
  					  & IPV6_TCLASS_MASK;
d24f22f3d   Eric Dumazet   ip6_tunnel: add o...
1037
1038
  	if (t->parms.flags & IP6_TNL_F_USE_ORIG_FWMARK)
  		fl6.flowi6_mark = skb->mark;
c4d3efafc   Yasuyuki Kozakai   [IPV6] IP6TUNNEL:...
1039

4c9483b2f   David S. Miller   ipv6: Convert to ...
1040
  	err = ip6_tnl_xmit2(skb, dev, dsfield, &fl6, encap_limit, &mtu);
c4d3efafc   Yasuyuki Kozakai   [IPV6] IP6TUNNEL:...
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
  	if (err != 0) {
  		/* XXX: send ICMP error even if DF is not set. */
  		if (err == -EMSGSIZE)
  			icmp_send(skb, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED,
  				  htonl(mtu));
  		return -1;
  	}
  
  	return 0;
  }
  
  static inline int
61ec2aec2   Yasuyuki Kozakai   [IPV6] IP6TUNNEL:...
1053
1054
1055
  ip6ip6_tnl_xmit(struct sk_buff *skb, struct net_device *dev)
  {
  	struct ip6_tnl *t = netdev_priv(dev);
0660e03f6   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
1056
  	struct ipv6hdr *ipv6h = ipv6_hdr(skb);
61ec2aec2   Yasuyuki Kozakai   [IPV6] IP6TUNNEL:...
1057
1058
  	int encap_limit = -1;
  	__u16 offset;
4c9483b2f   David S. Miller   ipv6: Convert to ...
1059
  	struct flowi6 fl6;
61ec2aec2   Yasuyuki Kozakai   [IPV6] IP6TUNNEL:...
1060
1061
1062
  	__u8 dsfield;
  	__u32 mtu;
  	int err;
502b09356   Yasuyuki Kozakai   [IPV6] IP6TUNNEL:...
1063
1064
  	if ((t->parms.proto != IPPROTO_IPV6 && t->parms.proto != 0) ||
  	    !ip6_tnl_xmit_ctl(t) || ip6_tnl_addr_conflict(t, ipv6h))
61ec2aec2   Yasuyuki Kozakai   [IPV6] IP6TUNNEL:...
1065
  		return -1;
c12b395a4   xeb@mail.ru   gre: Support GRE ...
1066
  	offset = ip6_tnl_parse_tlv_enc_lim(skb, skb_network_header(skb));
d56f90a7c   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
1067
  	if (offset > 0) {
61ec2aec2   Yasuyuki Kozakai   [IPV6] IP6TUNNEL:...
1068
  		struct ipv6_tlv_tnl_enc_lim *tel;
d56f90a7c   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
1069
  		tel = (struct ipv6_tlv_tnl_enc_lim *)&skb_network_header(skb)[offset];
61ec2aec2   Yasuyuki Kozakai   [IPV6] IP6TUNNEL:...
1070
1071
  		if (tel->encap_limit == 0) {
  			icmpv6_send(skb, ICMPV6_PARAMPROB,
3ffe533c8   Alexey Dobriyan   ipv6: drop unused...
1072
  				    ICMPV6_HDR_FIELD, offset + 2);
61ec2aec2   Yasuyuki Kozakai   [IPV6] IP6TUNNEL:...
1073
1074
1075
1076
1077
  			return -1;
  		}
  		encap_limit = tel->encap_limit - 1;
  	} else if (!(t->parms.flags & IP6_TNL_F_IGN_ENCAP_LIMIT))
  		encap_limit = t->parms.encap_limit;
4c9483b2f   David S. Miller   ipv6: Convert to ...
1078
1079
  	memcpy(&fl6, &t->fl.u.ip6, sizeof (fl6));
  	fl6.flowi6_proto = IPPROTO_IPV6;
61ec2aec2   Yasuyuki Kozakai   [IPV6] IP6TUNNEL:...
1080
1081
  
  	dsfield = ipv6_get_dsfield(ipv6h);
d24f22f3d   Eric Dumazet   ip6_tunnel: add o...
1082
  	if (t->parms.flags & IP6_TNL_F_USE_ORIG_TCLASS)
4c9483b2f   David S. Miller   ipv6: Convert to ...
1083
  		fl6.flowlabel |= (*(__be32 *) ipv6h & IPV6_TCLASS_MASK);
d24f22f3d   Eric Dumazet   ip6_tunnel: add o...
1084
  	if (t->parms.flags & IP6_TNL_F_USE_ORIG_FLOWLABEL)
4c9483b2f   David S. Miller   ipv6: Convert to ...
1085
  		fl6.flowlabel |= (*(__be32 *) ipv6h & IPV6_FLOWLABEL_MASK);
d24f22f3d   Eric Dumazet   ip6_tunnel: add o...
1086
1087
  	if (t->parms.flags & IP6_TNL_F_USE_ORIG_FWMARK)
  		fl6.flowi6_mark = skb->mark;
61ec2aec2   Yasuyuki Kozakai   [IPV6] IP6TUNNEL:...
1088

4c9483b2f   David S. Miller   ipv6: Convert to ...
1089
  	err = ip6_tnl_xmit2(skb, dev, dsfield, &fl6, encap_limit, &mtu);
61ec2aec2   Yasuyuki Kozakai   [IPV6] IP6TUNNEL:...
1090
1091
  	if (err != 0) {
  		if (err == -EMSGSIZE)
3ffe533c8   Alexey Dobriyan   ipv6: drop unused...
1092
  			icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu);
61ec2aec2   Yasuyuki Kozakai   [IPV6] IP6TUNNEL:...
1093
1094
1095
1096
1097
  		return -1;
  	}
  
  	return 0;
  }
6fef4c0c8   Stephen Hemminger   netdev: convert p...
1098
  static netdev_tx_t
61ec2aec2   Yasuyuki Kozakai   [IPV6] IP6TUNNEL:...
1099
1100
1101
  ip6_tnl_xmit(struct sk_buff *skb, struct net_device *dev)
  {
  	struct ip6_tnl *t = netdev_priv(dev);
3dca02af3   Pavel Emelyanov   ip6tnl: Use on-de...
1102
  	struct net_device_stats *stats = &t->dev->stats;
61ec2aec2   Yasuyuki Kozakai   [IPV6] IP6TUNNEL:...
1103
  	int ret;
61ec2aec2   Yasuyuki Kozakai   [IPV6] IP6TUNNEL:...
1104
  	switch (skb->protocol) {
606780404   Arnaldo Carvalho de Melo   net: Use hton[sl]...
1105
  	case htons(ETH_P_IP):
c4d3efafc   Yasuyuki Kozakai   [IPV6] IP6TUNNEL:...
1106
1107
  		ret = ip4ip6_tnl_xmit(skb, dev);
  		break;
606780404   Arnaldo Carvalho de Melo   net: Use hton[sl]...
1108
  	case htons(ETH_P_IPV6):
61ec2aec2   Yasuyuki Kozakai   [IPV6] IP6TUNNEL:...
1109
1110
1111
1112
1113
1114
1115
1116
  		ret = ip6ip6_tnl_xmit(skb, dev);
  		break;
  	default:
  		goto tx_err;
  	}
  
  	if (ret < 0)
  		goto tx_err;
6ed106549   Patrick McHardy   net: use NETDEV_T...
1117
  	return NETDEV_TX_OK;
61ec2aec2   Yasuyuki Kozakai   [IPV6] IP6TUNNEL:...
1118

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1119
1120
1121
1122
  tx_err:
  	stats->tx_errors++;
  	stats->tx_dropped++;
  	kfree_skb(skb);
6ed106549   Patrick McHardy   net: use NETDEV_T...
1123
  	return NETDEV_TX_OK;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1124
  }
3144581cb   Yasuyuki Kozakai   [IPV6] IP6TUNNEL:...
1125
  static void ip6_tnl_link_config(struct ip6_tnl *t)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1126
1127
  {
  	struct net_device *dev = t->dev;
c12b395a4   xeb@mail.ru   gre: Support GRE ...
1128
  	struct __ip6_tnl_parm *p = &t->parms;
4c9483b2f   David S. Miller   ipv6: Convert to ...
1129
  	struct flowi6 *fl6 = &t->fl.u.ip6;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1130

3a6d54c56   Jiri Pirko   net: remove needl...
1131
1132
  	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
1133
1134
  
  	/* Set up flowi template */
4e3fd7a06   Alexey Dobriyan   net: remove ipv6_...
1135
1136
  	fl6->saddr = p->laddr;
  	fl6->daddr = p->raddr;
4c9483b2f   David S. Miller   ipv6: Convert to ...
1137
1138
  	fl6->flowi6_oif = p->link;
  	fl6->flowlabel = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1139
1140
  
  	if (!(p->flags&IP6_TNL_F_USE_ORIG_TCLASS))
4c9483b2f   David S. Miller   ipv6: Convert to ...
1141
  		fl6->flowlabel |= IPV6_TCLASS_MASK & p->flowinfo;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1142
  	if (!(p->flags&IP6_TNL_F_USE_ORIG_FLOWLABEL))
4c9483b2f   David S. Miller   ipv6: Convert to ...
1143
  		fl6->flowlabel |= IPV6_FLOWLABEL_MASK & p->flowinfo;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1144

d0087b29f   Ville Nuorvala   ipv6_tunnel: Allo...
1145
1146
  	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
1147
1148
1149
1150
1151
1152
1153
1154
1155
  
  	if (p->flags&IP6_TNL_F_CAP_XMIT && p->flags&IP6_TNL_F_CAP_RCV)
  		dev->flags |= IFF_POINTOPOINT;
  	else
  		dev->flags &= ~IFF_POINTOPOINT;
  
  	dev->iflink = p->link;
  
  	if (p->flags & IP6_TNL_F_CAP_XMIT) {
305d4b3ce   Ville Nuorvala   [IPV6]: Allow lin...
1156
1157
  		int strict = (ipv6_addr_type(&p->raddr) &
  			      (IPV6_ADDR_MULTICAST|IPV6_ADDR_LINKLOCAL));
2f7f54b72   Pavel Emelyanov   [IP6TUNNEL]: Use ...
1158
1159
  		struct rt6_info *rt = rt6_lookup(dev_net(dev),
  						 &p->raddr, &p->laddr,
305d4b3ce   Ville Nuorvala   [IPV6]: Allow lin...
1160
  						 p->link, strict);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1161
1162
1163
  
  		if (rt == NULL)
  			return;
d19185428   David S. Miller   ipv6: Kill rt6i_d...
1164
1165
  		if (rt->dst.dev) {
  			dev->hard_header_len = rt->dst.dev->hard_header_len +
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1166
  				sizeof (struct ipv6hdr);
d19185428   David S. Miller   ipv6: Kill rt6i_d...
1167
  			dev->mtu = rt->dst.dev->mtu - sizeof (struct ipv6hdr);
381601e5b   Anders Franzen   Make the ip6_tunn...
1168
1169
  			if (!(t->parms.flags & IP6_TNL_F_IGN_ENCAP_LIMIT))
  				dev->mtu-=8;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1170
1171
1172
1173
  
  			if (dev->mtu < IPV6_MIN_MTU)
  				dev->mtu = IPV6_MIN_MTU;
  		}
94e187c01   Amerigo Wang   ipv6: introduce i...
1174
  		ip6_rt_put(rt);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1175
1176
1177
1178
  	}
  }
  
  /**
3144581cb   Yasuyuki Kozakai   [IPV6] IP6TUNNEL:...
1179
   * ip6_tnl_change - update the tunnel parameters
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1180
1181
   *   @t: tunnel to be changed
   *   @p: tunnel configuration parameters
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1182
1183
   *
   * Description:
3144581cb   Yasuyuki Kozakai   [IPV6] IP6TUNNEL:...
1184
   *   ip6_tnl_change() updates the tunnel parameters
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1185
1186
1187
   **/
  
  static int
c12b395a4   xeb@mail.ru   gre: Support GRE ...
1188
  ip6_tnl_change(struct ip6_tnl *t, const struct __ip6_tnl_parm *p)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1189
  {
4e3fd7a06   Alexey Dobriyan   net: remove ipv6_...
1190
1191
  	t->parms.laddr = p->laddr;
  	t->parms.raddr = p->raddr;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1192
1193
1194
1195
  	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...
1196
  	t->parms.link = p->link;
502b09356   Yasuyuki Kozakai   [IPV6] IP6TUNNEL:...
1197
  	t->parms.proto = p->proto;
0c0888908   Hugo Santos   [IPV6] ip6_tunnel...
1198
  	ip6_tnl_dst_reset(t);
3144581cb   Yasuyuki Kozakai   [IPV6] IP6TUNNEL:...
1199
  	ip6_tnl_link_config(t);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1200
1201
  	return 0;
  }
0b1124572   Nicolas Dichtel   ip6tnl: add suppo...
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
  static int ip6_tnl_update(struct ip6_tnl *t, struct __ip6_tnl_parm *p)
  {
  	struct net *net = dev_net(t->dev);
  	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;
  }
c12b395a4   xeb@mail.ru   gre: Support GRE ...
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
  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
1242
  /**
3144581cb   Yasuyuki Kozakai   [IPV6] IP6TUNNEL:...
1243
   * ip6_tnl_ioctl - configure ipv6 tunnels from userspace
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1244
1245
1246
1247
1248
   *   @dev: virtual device associated with tunnel
   *   @ifr: parameters passed from userspace
   *   @cmd: command to be performed
   *
   * Description:
3144581cb   Yasuyuki Kozakai   [IPV6] IP6TUNNEL:...
1249
   *   ip6_tnl_ioctl() is used for managing IPv6 tunnels
1ab1457c4   YOSHIFUJI Hideaki   [NET] IPV6: Fix w...
1250
   *   from userspace.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1251
1252
1253
1254
1255
1256
1257
   *
   *   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...
1258
   *   The fallback device "ip6tnl0", created during module
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
   *   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:...
1271
  ip6_tnl_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1272
1273
  {
  	int err = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1274
  	struct ip6_tnl_parm p;
c12b395a4   xeb@mail.ru   gre: Support GRE ...
1275
  	struct __ip6_tnl_parm p1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1276
  	struct ip6_tnl *t = NULL;
2dd02c897   Pavel Emelyanov   [IP6TUNNEL]: Add ...
1277
1278
  	struct net *net = dev_net(dev);
  	struct ip6_tnl_net *ip6n = net_generic(net, ip6_tnl_net_id);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1279
1280
1281
  
  	switch (cmd) {
  	case SIOCGETTUNNEL:
15820e129   Pavel Emelyanov   [IP6TUNNEL]: Make...
1282
  		if (dev == ip6n->fb_tnl_dev) {
567131a72   Ville Nuorvala   [IPV6]: Fix SIOCC...
1283
  			if (copy_from_user(&p, ifr->ifr_ifru.ifru_data, sizeof (p))) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1284
1285
1286
  				err = -EFAULT;
  				break;
  			}
c12b395a4   xeb@mail.ru   gre: Support GRE ...
1287
1288
  			ip6_tnl_parm_from_user(&p1, &p);
  			t = ip6_tnl_locate(net, &p1, 0);
5ef5d6c56   Dan Carpenter   gre: information ...
1289
1290
  		} else {
  			memset(&p, 0, sizeof(p));
567131a72   Ville Nuorvala   [IPV6]: Fix SIOCC...
1291
1292
  		}
  		if (t == NULL)
2941a4863   Patrick McHardy   [NET]: Convert ne...
1293
  			t = netdev_priv(dev);
c12b395a4   xeb@mail.ru   gre: Support GRE ...
1294
  		ip6_tnl_parm_to_user(&p, &t->parms);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1295
1296
1297
1298
1299
1300
1301
  		if (copy_to_user(ifr->ifr_ifru.ifru_data, &p, sizeof (p))) {
  			err = -EFAULT;
  		}
  		break;
  	case SIOCADDTUNNEL:
  	case SIOCCHGTUNNEL:
  		err = -EPERM;
af31f412c   Eric W. Biederman   net: Allow userns...
1302
  		if (!ns_capable(net->user_ns, CAP_NET_ADMIN))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1303
  			break;
567131a72   Ville Nuorvala   [IPV6]: Fix SIOCC...
1304
1305
  		err = -EFAULT;
  		if (copy_from_user(&p, ifr->ifr_ifru.ifru_data, sizeof (p)))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1306
  			break;
567131a72   Ville Nuorvala   [IPV6]: Fix SIOCC...
1307
  		err = -EINVAL;
502b09356   Yasuyuki Kozakai   [IPV6] IP6TUNNEL:...
1308
1309
  		if (p.proto != IPPROTO_IPV6 && p.proto != IPPROTO_IPIP &&
  		    p.proto != 0)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1310
  			break;
c12b395a4   xeb@mail.ru   gre: Support GRE ...
1311
1312
  		ip6_tnl_parm_from_user(&p1, &p);
  		t = ip6_tnl_locate(net, &p1, cmd == SIOCADDTUNNEL);
15820e129   Pavel Emelyanov   [IP6TUNNEL]: Make...
1313
  		if (dev != ip6n->fb_tnl_dev && cmd == SIOCCHGTUNNEL) {
567131a72   Ville Nuorvala   [IPV6]: Fix SIOCC...
1314
1315
1316
1317
1318
1319
1320
  			if (t != NULL) {
  				if (t->dev != dev) {
  					err = -EEXIST;
  					break;
  				}
  			} else
  				t = netdev_priv(dev);
0b1124572   Nicolas Dichtel   ip6tnl: add suppo...
1321
  			err = ip6_tnl_update(t, &p1);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1322
  		}
567131a72   Ville Nuorvala   [IPV6]: Fix SIOCC...
1323
  		if (t) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1324
  			err = 0;
c12b395a4   xeb@mail.ru   gre: Support GRE ...
1325
1326
  			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...
1327
1328
1329
1330
  				err = -EFAULT;
  
  		} else
  			err = (cmd == SIOCADDTUNNEL ? -ENOBUFS : -ENOENT);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1331
1332
1333
  		break;
  	case SIOCDELTUNNEL:
  		err = -EPERM;
af31f412c   Eric W. Biederman   net: Allow userns...
1334
  		if (!ns_capable(net->user_ns, CAP_NET_ADMIN))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1335
  			break;
15820e129   Pavel Emelyanov   [IP6TUNNEL]: Make...
1336
  		if (dev == ip6n->fb_tnl_dev) {
567131a72   Ville Nuorvala   [IPV6]: Fix SIOCC...
1337
1338
  			err = -EFAULT;
  			if (copy_from_user(&p, ifr->ifr_ifru.ifru_data, sizeof (p)))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1339
  				break;
567131a72   Ville Nuorvala   [IPV6]: Fix SIOCC...
1340
  			err = -ENOENT;
c12b395a4   xeb@mail.ru   gre: Support GRE ...
1341
1342
1343
  			ip6_tnl_parm_from_user(&p1, &p);
  			t = ip6_tnl_locate(net, &p1, 0);
  			if (t == NULL)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1344
  				break;
567131a72   Ville Nuorvala   [IPV6]: Fix SIOCC...
1345
  			err = -EPERM;
15820e129   Pavel Emelyanov   [IP6TUNNEL]: Make...
1346
  			if (t->dev == ip6n->fb_tnl_dev)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1347
  				break;
567131a72   Ville Nuorvala   [IPV6]: Fix SIOCC...
1348
  			dev = t->dev;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1349
  		}
22f8cde5b   Stephen Hemminger   [NET]: unregister...
1350
1351
  		err = 0;
  		unregister_netdevice(dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1352
1353
1354
1355
1356
1357
1358
1359
  		break;
  	default:
  		err = -EINVAL;
  	}
  	return err;
  }
  
  /**
3144581cb   Yasuyuki Kozakai   [IPV6] IP6TUNNEL:...
1360
   * ip6_tnl_change_mtu - change mtu manually for tunnel device
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1361
1362
1363
1364
1365
1366
1367
1368
1369
   *   @dev: virtual device associated with tunnel
   *   @new_mtu: the new mtu
   *
   * Return:
   *   0 on success,
   *   %-EINVAL if mtu too small
   **/
  
  static int
3144581cb   Yasuyuki Kozakai   [IPV6] IP6TUNNEL:...
1370
  ip6_tnl_change_mtu(struct net_device *dev, int new_mtu)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1371
1372
1373
1374
1375
1376
1377
  {
  	if (new_mtu < IPV6_MIN_MTU) {
  		return -EINVAL;
  	}
  	dev->mtu = new_mtu;
  	return 0;
  }
1326c3d5a   Stephen Hemminger   ipv6: convert tun...
1378
1379
  
  static const struct net_device_ops ip6_tnl_netdev_ops = {
8560f2266   Eric Dumazet   ip6tnl: percpu st...
1380
  	.ndo_uninit	= ip6_tnl_dev_uninit,
1326c3d5a   Stephen Hemminger   ipv6: convert tun...
1381
  	.ndo_start_xmit = ip6_tnl_xmit,
8560f2266   Eric Dumazet   ip6tnl: percpu st...
1382
  	.ndo_do_ioctl	= ip6_tnl_ioctl,
1326c3d5a   Stephen Hemminger   ipv6: convert tun...
1383
  	.ndo_change_mtu = ip6_tnl_change_mtu,
8560f2266   Eric Dumazet   ip6tnl: percpu st...
1384
  	.ndo_get_stats	= ip6_get_stats,
1326c3d5a   Stephen Hemminger   ipv6: convert tun...
1385
  };
8560f2266   Eric Dumazet   ip6tnl: percpu st...
1386

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1387
  /**
3144581cb   Yasuyuki Kozakai   [IPV6] IP6TUNNEL:...
1388
   * ip6_tnl_dev_setup - setup virtual tunnel device
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1389
1390
1391
1392
1393
   *   @dev: virtual device associated with tunnel
   *
   * Description:
   *   Initialize function pointers and device parameters
   **/
3144581cb   Yasuyuki Kozakai   [IPV6] IP6TUNNEL:...
1394
  static void ip6_tnl_dev_setup(struct net_device *dev)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1395
  {
381601e5b   Anders Franzen   Make the ip6_tunn...
1396
  	struct ip6_tnl *t;
1326c3d5a   Stephen Hemminger   ipv6: convert tun...
1397
  	dev->netdev_ops = &ip6_tnl_netdev_ops;
8560f2266   Eric Dumazet   ip6tnl: percpu st...
1398
  	dev->destructor = ip6_dev_free;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1399
1400
1401
1402
  
  	dev->type = ARPHRD_TUNNEL6;
  	dev->hard_header_len = LL_MAX_HEADER + sizeof (struct ipv6hdr);
  	dev->mtu = ETH_DATA_LEN - sizeof (struct ipv6hdr);
381601e5b   Anders Franzen   Make the ip6_tunn...
1403
1404
1405
  	t = netdev_priv(dev);
  	if (!(t->parms.flags & IP6_TNL_F_IGN_ENCAP_LIMIT))
  		dev->mtu-=8;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1406
1407
  	dev->flags |= IFF_NOARP;
  	dev->addr_len = sizeof(struct in6_addr);
554eb2778   Pavel Emelyanov   [IP6TUNNEL]: Allo...
1408
  	dev->features |= NETIF_F_NETNS_LOCAL;
7e223de84   Anders Franzen   ip6_tunnel dont u...
1409
  	dev->priv_flags &= ~IFF_XMIT_DST_RELEASE;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1410
1411
1412
1413
  }
  
  
  /**
3144581cb   Yasuyuki Kozakai   [IPV6] IP6TUNNEL:...
1414
   * ip6_tnl_dev_init_gen - general initializer for all tunnel devices
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1415
1416
   *   @dev: virtual device associated with tunnel
   **/
8560f2266   Eric Dumazet   ip6tnl: percpu st...
1417
  static inline int
3144581cb   Yasuyuki Kozakai   [IPV6] IP6TUNNEL:...
1418
  ip6_tnl_dev_init_gen(struct net_device *dev)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1419
  {
2941a4863   Patrick McHardy   [NET]: Convert ne...
1420
  	struct ip6_tnl *t = netdev_priv(dev);
8560f2266   Eric Dumazet   ip6tnl: percpu st...
1421

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1422
  	t->dev = dev;
8560f2266   Eric Dumazet   ip6tnl: percpu st...
1423
1424
1425
1426
  	dev->tstats = alloc_percpu(struct pcpu_tstats);
  	if (!dev->tstats)
  		return -ENOMEM;
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1427
1428
1429
  }
  
  /**
3144581cb   Yasuyuki Kozakai   [IPV6] IP6TUNNEL:...
1430
   * ip6_tnl_dev_init - initializer for all non fallback tunnel devices
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1431
1432
   *   @dev: virtual device associated with tunnel
   **/
8560f2266   Eric Dumazet   ip6tnl: percpu st...
1433
  static int ip6_tnl_dev_init(struct net_device *dev)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1434
  {
2941a4863   Patrick McHardy   [NET]: Convert ne...
1435
  	struct ip6_tnl *t = netdev_priv(dev);
8560f2266   Eric Dumazet   ip6tnl: percpu st...
1436
1437
1438
1439
  	int err = ip6_tnl_dev_init_gen(dev);
  
  	if (err)
  		return err;
3144581cb   Yasuyuki Kozakai   [IPV6] IP6TUNNEL:...
1440
  	ip6_tnl_link_config(t);
8560f2266   Eric Dumazet   ip6tnl: percpu st...
1441
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1442
1443
1444
  }
  
  /**
3144581cb   Yasuyuki Kozakai   [IPV6] IP6TUNNEL:...
1445
   * ip6_fb_tnl_dev_init - initializer for fallback tunnel device
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1446
1447
1448
1449
   *   @dev: fallback device
   *
   * Return: 0
   **/
8560f2266   Eric Dumazet   ip6tnl: percpu st...
1450
  static int __net_init ip6_fb_tnl_dev_init(struct net_device *dev)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1451
  {
2941a4863   Patrick McHardy   [NET]: Convert ne...
1452
  	struct ip6_tnl *t = netdev_priv(dev);
3e6c9fb5f   Pavel Emelyanov   [IP6TUNNEL]: Make...
1453
1454
  	struct net *net = dev_net(dev);
  	struct ip6_tnl_net *ip6n = net_generic(net, ip6_tnl_net_id);
8560f2266   Eric Dumazet   ip6tnl: percpu st...
1455
1456
1457
1458
  	int err = ip6_tnl_dev_init_gen(dev);
  
  	if (err)
  		return err;
3e6c9fb5f   Pavel Emelyanov   [IP6TUNNEL]: Make...
1459

502b09356   Yasuyuki Kozakai   [IPV6] IP6TUNNEL:...
1460
  	t->parms.proto = IPPROTO_IPV6;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1461
  	dev_hold(dev);
d0087b29f   Ville Nuorvala   ipv6_tunnel: Allo...
1462
1463
  
  	ip6_tnl_link_config(t);
cf778b00e   Eric Dumazet   net: reintroduce ...
1464
  	rcu_assign_pointer(ip6n->tnls_wc[0], t);
8560f2266   Eric Dumazet   ip6tnl: percpu st...
1465
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1466
  }
0b1124572   Nicolas Dichtel   ip6tnl: add suppo...
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
  static int ip6_tnl_validate(struct nlattr *tb[], struct nlattr *data[])
  {
  	u8 proto;
  
  	if (!data)
  		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])
  		nla_memcpy(&parms->laddr, data[IFLA_IPTUN_LOCAL],
  			   sizeof(struct in6_addr));
  
  	if (data[IFLA_IPTUN_REMOTE])
  		nla_memcpy(&parms->raddr, data[IFLA_IPTUN_REMOTE],
  			   sizeof(struct in6_addr));
  
  	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...
1509
  		parms->flowinfo = nla_get_be32(data[IFLA_IPTUN_FLOWINFO]);
0b1124572   Nicolas Dichtel   ip6tnl: add suppo...
1510
1511
1512
1513
1514
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
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
  
  	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]);
  }
  
  static int ip6_tnl_newlink(struct net *src_net, struct net_device *dev,
  			   struct nlattr *tb[], struct nlattr *data[])
  {
  	struct net *net = dev_net(dev);
  	struct ip6_tnl *nt;
  
  	nt = netdev_priv(dev);
  	ip6_tnl_netlink_parms(data, &nt->parms);
  
  	if (ip6_tnl_locate(net, &nt->parms, 0))
  		return -EEXIST;
  
  	return ip6_tnl_create2(dev);
  }
  
  static int ip6_tnl_changelink(struct net_device *dev, struct nlattr *tb[],
  			      struct nlattr *data[])
  {
  	struct ip6_tnl *t;
  	struct __ip6_tnl_parm p;
  	struct net *net = dev_net(dev);
  	struct ip6_tnl_net *ip6n = net_generic(net, ip6_tnl_net_id);
  
  	if (dev == ip6n->fb_tnl_dev)
  		return -EINVAL;
  
  	ip6_tnl_netlink_parms(data, &p);
  
  	t = ip6_tnl_locate(net, &p, 0);
  
  	if (t) {
  		if (t->dev != dev)
  			return -EEXIST;
  	} else
  		t = netdev_priv(dev);
  
  	return ip6_tnl_update(t, &p);
  }
b58d731ac   Nicolas Dichtel   ip6tnl: rename rt...
1556
  static size_t ip6_tnl_get_size(const struct net_device *dev)
c075b1309   Nicolas Dichtel   ip6tnl: advertise...
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
  {
  	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 ...
1573
1574
  		/* IFLA_IPTUN_PROTO */
  		nla_total_size(1) +
c075b1309   Nicolas Dichtel   ip6tnl: advertise...
1575
1576
  		0;
  }
b58d731ac   Nicolas Dichtel   ip6tnl: rename rt...
1577
  static int ip6_tnl_fill_info(struct sk_buff *skb, const struct net_device *dev)
c075b1309   Nicolas Dichtel   ip6tnl: advertise...
1578
1579
1580
1581
1582
1583
  {
  	struct ip6_tnl *tunnel = netdev_priv(dev);
  	struct __ip6_tnl_parm *parm = &tunnel->parms;
  
  	if (nla_put_u32(skb, IFLA_IPTUN_LINK, parm->link) ||
  	    nla_put(skb, IFLA_IPTUN_LOCAL, sizeof(struct in6_addr),
c075b1309   Nicolas Dichtel   ip6tnl: advertise...
1584
  		    &parm->laddr) ||
fa42a01cb   Ding Zhi   ip6_tunnels: radd...
1585
1586
  	    nla_put(skb, IFLA_IPTUN_REMOTE, sizeof(struct in6_addr),
  		    &parm->raddr) ||
c075b1309   Nicolas Dichtel   ip6tnl: advertise...
1587
1588
1589
  	    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 ...
1590
1591
  	    nla_put_u32(skb, IFLA_IPTUN_FLAGS, parm->flags) ||
  	    nla_put_u8(skb, IFLA_IPTUN_PROTO, parm->proto))
c075b1309   Nicolas Dichtel   ip6tnl: advertise...
1592
1593
1594
1595
1596
1597
  		goto nla_put_failure;
  	return 0;
  
  nla_put_failure:
  	return -EMSGSIZE;
  }
0b1124572   Nicolas Dichtel   ip6tnl: add suppo...
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
  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 },
  };
c075b1309   Nicolas Dichtel   ip6tnl: advertise...
1608
1609
1610
  static struct rtnl_link_ops ip6_link_ops __read_mostly = {
  	.kind		= "ip6tnl",
  	.maxtype	= IFLA_IPTUN_MAX,
0b1124572   Nicolas Dichtel   ip6tnl: add suppo...
1611
  	.policy		= ip6_tnl_policy,
c075b1309   Nicolas Dichtel   ip6tnl: advertise...
1612
  	.priv_size	= sizeof(struct ip6_tnl),
0b1124572   Nicolas Dichtel   ip6tnl: add suppo...
1613
1614
1615
1616
  	.setup		= ip6_tnl_dev_setup,
  	.validate	= ip6_tnl_validate,
  	.newlink	= ip6_tnl_newlink,
  	.changelink	= ip6_tnl_changelink,
b58d731ac   Nicolas Dichtel   ip6tnl: rename rt...
1617
1618
  	.get_size	= ip6_tnl_get_size,
  	.fill_info	= ip6_tnl_fill_info,
c075b1309   Nicolas Dichtel   ip6tnl: advertise...
1619
  };
3ff2cfa55   Eric Dumazet   ipv6: struct xfrm...
1620
  static struct xfrm6_tunnel ip4ip6_handler __read_mostly = {
c4d3efafc   Yasuyuki Kozakai   [IPV6] IP6TUNNEL:...
1621
1622
1623
1624
  	.handler	= ip4ip6_rcv,
  	.err_handler	= ip4ip6_err,
  	.priority	=	1,
  };
3ff2cfa55   Eric Dumazet   ipv6: struct xfrm...
1625
  static struct xfrm6_tunnel ip6ip6_handler __read_mostly = {
0303770de   Patrick McHardy   [NET]: Make ipip/...
1626
1627
  	.handler	= ip6ip6_rcv,
  	.err_handler	= ip6ip6_err,
d2acc3479   Herbert Xu   [INET]: Introduce...
1628
  	.priority	=	1,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1629
  };
2c8c1e729   Alexey Dobriyan   net: spread __net...
1630
  static void __net_exit ip6_tnl_destroy_tunnels(struct ip6_tnl_net *ip6n)
3e6c9fb5f   Pavel Emelyanov   [IP6TUNNEL]: Make...
1631
1632
1633
  {
  	int h;
  	struct ip6_tnl *t;
cf4432f55   Eric Dumazet   ip6tnl: Optimize ...
1634
  	LIST_HEAD(list);
3e6c9fb5f   Pavel Emelyanov   [IP6TUNNEL]: Make...
1635
1636
  
  	for (h = 0; h < HASH_SIZE; h++) {
947676326   Eric Dumazet   ip6tnl: get rid o...
1637
  		t = rtnl_dereference(ip6n->tnls_r_l[h]);
cf4432f55   Eric Dumazet   ip6tnl: Optimize ...
1638
1639
  		while (t != NULL) {
  			unregister_netdevice_queue(t->dev, &list);
947676326   Eric Dumazet   ip6tnl: get rid o...
1640
  			t = rtnl_dereference(t->next);
cf4432f55   Eric Dumazet   ip6tnl: Optimize ...
1641
  		}
3e6c9fb5f   Pavel Emelyanov   [IP6TUNNEL]: Make...
1642
  	}
947676326   Eric Dumazet   ip6tnl: get rid o...
1643
  	t = rtnl_dereference(ip6n->tnls_wc[0]);
cf4432f55   Eric Dumazet   ip6tnl: Optimize ...
1644
1645
  	unregister_netdevice_queue(t->dev, &list);
  	unregister_netdevice_many(&list);
3e6c9fb5f   Pavel Emelyanov   [IP6TUNNEL]: Make...
1646
  }
2c8c1e729   Alexey Dobriyan   net: spread __net...
1647
  static int __net_init ip6_tnl_init_net(struct net *net)
13eeb8e92   Pavel Emelyanov   [IP6TUNNEL]: Intr...
1648
  {
ac31cd3cb   Eric W. Biederman   net: Simplify ip6...
1649
  	struct ip6_tnl_net *ip6n = net_generic(net, ip6_tnl_net_id);
731abb9cb   Josh Boyer   ip6_tunnel: copy ...
1650
  	struct ip6_tnl *t = NULL;
13eeb8e92   Pavel Emelyanov   [IP6TUNNEL]: Intr...
1651
  	int err;
13eeb8e92   Pavel Emelyanov   [IP6TUNNEL]: Intr...
1652

3e6c9fb5f   Pavel Emelyanov   [IP6TUNNEL]: Make...
1653
1654
  	ip6n->tnls[0] = ip6n->tnls_wc;
  	ip6n->tnls[1] = ip6n->tnls_r_l;
15820e129   Pavel Emelyanov   [IP6TUNNEL]: Make...
1655
1656
1657
1658
1659
1660
  	err = -ENOMEM;
  	ip6n->fb_tnl_dev = alloc_netdev(sizeof(struct ip6_tnl), "ip6tnl0",
  				      ip6_tnl_dev_setup);
  
  	if (!ip6n->fb_tnl_dev)
  		goto err_alloc_dev;
be77e5930   Alexey Dobriyan   net: fix tunnels ...
1661
  	dev_net_set(ip6n->fb_tnl_dev, net);
506cdb890   Nicolas Dichtel   ip6tnl: allow to ...
1662
  	ip6n->fb_tnl_dev->rtnl_link_ops = &ip6_link_ops;
15820e129   Pavel Emelyanov   [IP6TUNNEL]: Make...
1663

8560f2266   Eric Dumazet   ip6tnl: percpu st...
1664
1665
1666
  	err = ip6_fb_tnl_dev_init(ip6n->fb_tnl_dev);
  	if (err < 0)
  		goto err_register;
15820e129   Pavel Emelyanov   [IP6TUNNEL]: Make...
1667
1668
1669
1670
  
  	err = register_netdev(ip6n->fb_tnl_dev);
  	if (err < 0)
  		goto err_register;
731abb9cb   Josh Boyer   ip6_tunnel: copy ...
1671
1672
1673
1674
  
  	t = netdev_priv(ip6n->fb_tnl_dev);
  
  	strcpy(t->parms.name, ip6n->fb_tnl_dev->name);
13eeb8e92   Pavel Emelyanov   [IP6TUNNEL]: Intr...
1675
  	return 0;
15820e129   Pavel Emelyanov   [IP6TUNNEL]: Make...
1676
  err_register:
8560f2266   Eric Dumazet   ip6tnl: percpu st...
1677
  	ip6_dev_free(ip6n->fb_tnl_dev);
15820e129   Pavel Emelyanov   [IP6TUNNEL]: Make...
1678
  err_alloc_dev:
13eeb8e92   Pavel Emelyanov   [IP6TUNNEL]: Intr...
1679
1680
  	return err;
  }
2c8c1e729   Alexey Dobriyan   net: spread __net...
1681
  static void __net_exit ip6_tnl_exit_net(struct net *net)
13eeb8e92   Pavel Emelyanov   [IP6TUNNEL]: Intr...
1682
  {
ac31cd3cb   Eric W. Biederman   net: Simplify ip6...
1683
  	struct ip6_tnl_net *ip6n = net_generic(net, ip6_tnl_net_id);
13eeb8e92   Pavel Emelyanov   [IP6TUNNEL]: Intr...
1684

3e6c9fb5f   Pavel Emelyanov   [IP6TUNNEL]: Make...
1685
1686
1687
  	rtnl_lock();
  	ip6_tnl_destroy_tunnels(ip6n);
  	rtnl_unlock();
13eeb8e92   Pavel Emelyanov   [IP6TUNNEL]: Intr...
1688
1689
1690
1691
1692
  }
  
  static struct pernet_operations ip6_tnl_net_ops = {
  	.init = ip6_tnl_init_net,
  	.exit = ip6_tnl_exit_net,
ac31cd3cb   Eric W. Biederman   net: Simplify ip6...
1693
1694
  	.id   = &ip6_tnl_net_id,
  	.size = sizeof(struct ip6_tnl_net),
13eeb8e92   Pavel Emelyanov   [IP6TUNNEL]: Intr...
1695
  };
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1696
1697
1698
1699
1700
1701
1702
1703
1704
  /**
   * ip6_tunnel_init - register protocol and reserve needed resources
   *
   * Return: 0 on success
   **/
  
  static int __init ip6_tunnel_init(void)
  {
  	int  err;
d5aa407f5   Alexey Dobriyan   tunnels: fix netn...
1705
1706
1707
1708
1709
1710
  	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...
1711
1712
  		pr_err("%s: can't register ip4ip6
  ", __func__);
d5aa407f5   Alexey Dobriyan   tunnels: fix netn...
1713
  		goto out_ip4ip6;
c4d3efafc   Yasuyuki Kozakai   [IPV6] IP6TUNNEL:...
1714
  	}
d5aa407f5   Alexey Dobriyan   tunnels: fix netn...
1715
1716
  	err = xfrm6_tunnel_register(&ip6ip6_handler, AF_INET6);
  	if (err < 0) {
f32138319   Joe Perches   net: ipv6: Standa...
1717
1718
  		pr_err("%s: can't register ip6ip6
  ", __func__);
d5aa407f5   Alexey Dobriyan   tunnels: fix netn...
1719
  		goto out_ip6ip6;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1720
  	}
c075b1309   Nicolas Dichtel   ip6tnl: advertise...
1721
1722
1723
  	err = rtnl_link_register(&ip6_link_ops);
  	if (err < 0)
  		goto rtnl_link_failed;
13eeb8e92   Pavel Emelyanov   [IP6TUNNEL]: Intr...
1724

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

c075b1309   Nicolas Dichtel   ip6tnl: advertise...
1727
1728
  rtnl_link_failed:
  	xfrm6_tunnel_deregister(&ip6ip6_handler, AF_INET6);
d5aa407f5   Alexey Dobriyan   tunnels: fix netn...
1729
  out_ip6ip6:
c4d3efafc   Yasuyuki Kozakai   [IPV6] IP6TUNNEL:...
1730
  	xfrm6_tunnel_deregister(&ip4ip6_handler, AF_INET);
d5aa407f5   Alexey Dobriyan   tunnels: fix netn...
1731
1732
1733
  out_ip4ip6:
  	unregister_pernet_device(&ip6_tnl_net_ops);
  out_pernet:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1734
1735
1736
1737
1738
1739
1740
1741
1742
  	return err;
  }
  
  /**
   * ip6_tunnel_cleanup - free resources and unregister protocol
   **/
  
  static void __exit ip6_tunnel_cleanup(void)
  {
c075b1309   Nicolas Dichtel   ip6tnl: advertise...
1743
  	rtnl_link_unregister(&ip6_link_ops);
c4d3efafc   Yasuyuki Kozakai   [IPV6] IP6TUNNEL:...
1744
  	if (xfrm6_tunnel_deregister(&ip4ip6_handler, AF_INET))
f32138319   Joe Perches   net: ipv6: Standa...
1745
1746
  		pr_info("%s: can't deregister ip4ip6
  ", __func__);
c4d3efafc   Yasuyuki Kozakai   [IPV6] IP6TUNNEL:...
1747

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

ac31cd3cb   Eric W. Biederman   net: Simplify ip6...
1752
  	unregister_pernet_device(&ip6_tnl_net_ops);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1753
1754
1755
1756
  }
  
  module_init(ip6_tunnel_init);
  module_exit(ip6_tunnel_cleanup);