ip_gre.c 42.1 KB
Newer Older
Linus Torvalds's avatar
Linus Torvalds committed
1
/*
2
 *	Linux NET3:	GRE over IP protocol decoder.
Linus Torvalds's avatar
Linus Torvalds committed
3
4
5
6
7
8
9
10
11
12
 *
 *	Authors: Alexey Kuznetsov (kuznet@ms2.inr.ac.ru)
 *
 *	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.
 *
 */

13
#include <linux/capability.h>
Linus Torvalds's avatar
Linus Torvalds committed
14
15
16
#include <linux/module.h>
#include <linux/types.h>
#include <linux/kernel.h>
17
#include <linux/slab.h>
Linus Torvalds's avatar
Linus Torvalds committed
18
19
20
21
22
23
24
25
26
27
28
29
30
#include <asm/uaccess.h>
#include <linux/skbuff.h>
#include <linux/netdevice.h>
#include <linux/in.h>
#include <linux/tcp.h>
#include <linux/udp.h>
#include <linux/if_arp.h>
#include <linux/mroute.h>
#include <linux/init.h>
#include <linux/in6.h>
#include <linux/inetdevice.h>
#include <linux/igmp.h>
#include <linux/netfilter_ipv4.h>
31
#include <linux/etherdevice.h>
32
#include <linux/if_ether.h>
Linus Torvalds's avatar
Linus Torvalds committed
33
34
35
36
37
38
39
40
41
42
43

#include <net/sock.h>
#include <net/ip.h>
#include <net/icmp.h>
#include <net/protocol.h>
#include <net/ipip.h>
#include <net/arp.h>
#include <net/checksum.h>
#include <net/dsfield.h>
#include <net/inet_ecn.h>
#include <net/xfrm.h>
44
45
#include <net/net_namespace.h>
#include <net/netns/generic.h>
Herbert Xu's avatar
Herbert Xu committed
46
#include <net/rtnetlink.h>
47
#include <net/gre.h>
Linus Torvalds's avatar
Linus Torvalds committed
48

49
#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
Linus Torvalds's avatar
Linus Torvalds committed
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
#include <net/ipv6.h>
#include <net/ip6_fib.h>
#include <net/ip6_route.h>
#endif

/*
   Problems & solutions
   --------------------

   1. The most important issue is detecting local dead loops.
   They would cause complete host lockup in transmit, which
   would be "resolved" by stack overflow or, if queueing is enabled,
   with infinite looping in net_bh.

   We cannot track such dead loops during route installation,
   it is infeasible task. The most general solutions would be
   to keep skb->encapsulation counter (sort of local ttl),
Eric Dumazet's avatar
Eric Dumazet committed
67
   and silently drop packet when it expires. It is a good
Linus Torvalds's avatar
Linus Torvalds committed
68
69
70
   solution, but it supposes maintaing new variable in ALL
   skb, even if no tunneling is used.

Eric Dumazet's avatar
Eric Dumazet committed
71
72
73
   Current solution: xmit_recursion breaks dead loops. This is a percpu
   counter, since when we enter the first ndo_xmit(), cpu migration is
   forbidden. We force an exit if this counter reaches RECURSION_LIMIT
Linus Torvalds's avatar
Linus Torvalds committed
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120

   2. Networking dead loops would not kill routers, but would really
   kill network. IP hop limit plays role of "t->recursion" in this case,
   if we copy it from packet being encapsulated to upper header.
   It is very good solution, but it introduces two problems:

   - Routing protocols, using packets with ttl=1 (OSPF, RIP2),
     do not work over tunnels.
   - traceroute does not work. I planned to relay ICMP from tunnel,
     so that this problem would be solved and traceroute output
     would even more informative. This idea appeared to be wrong:
     only Linux complies to rfc1812 now (yes, guys, Linux is the only
     true router now :-)), all routers (at least, in neighbourhood of mine)
     return only 8 bytes of payload. It is the end.

   Hence, if we want that OSPF worked or traceroute said something reasonable,
   we should search for another solution.

   One of them is to parse packet trying to detect inner encapsulation
   made by our node. It is difficult or even impossible, especially,
   taking into account fragmentation. TO be short, tt is not solution at all.

   Current solution: The solution was UNEXPECTEDLY SIMPLE.
   We force DF flag on tunnels with preconfigured hop limit,
   that is ALL. :-) Well, it does not remove the problem completely,
   but exponential growth of network traffic is changed to linear
   (branches, that exceed pmtu are pruned) and tunnel mtu
   fastly degrades to value <68, where looping stops.
   Yes, it is not good if there exists a router in the loop,
   which does not force DF, even when encapsulating packets have DF set.
   But it is not our problem! Nobody could accuse us, we made
   all that we could make. Even if it is your gated who injected
   fatal route to network, even if it were you who configured
   fatal static route: you are innocent. :-)



   3. Really, ipv4/ipip.c, ipv4/ip_gre.c and ipv6/sit.c contain
   practically identical code. It would be good to glue them
   together, but it is not very evident, how to make them modular.
   sit is integral part of IPv6, ipip and gre are naturally modular.
   We could extract common parts (hash table, ioctl etc)
   to a separate module (ip_tunnel.c).

   Alexey Kuznetsov.
 */

Herbert Xu's avatar
Herbert Xu committed
121
static struct rtnl_link_ops ipgre_link_ops __read_mostly;
Linus Torvalds's avatar
Linus Torvalds committed
122
123
static int ipgre_tunnel_init(struct net_device *dev);
static void ipgre_tunnel_setup(struct net_device *dev);
124
static int ipgre_tunnel_bind_dev(struct net_device *dev);
Linus Torvalds's avatar
Linus Torvalds committed
125
126
127

/* Fallback tunnel: no source, no destination, no key, no options */

128
129
#define HASH_SIZE  16

130
static int ipgre_net_id __read_mostly;
131
struct ipgre_net {
Eric Dumazet's avatar
Eric Dumazet committed
132
	struct ip_tunnel __rcu *tunnels[4][HASH_SIZE];
133

134
	struct net_device *fb_tunnel_dev;
135
136
};

Linus Torvalds's avatar
Linus Torvalds committed
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
/* Tunnel hash table */

/*
   4 hash tables:

   3: (remote,local)
   2: (remote,*)
   1: (*,local)
   0: (*,*)

   We require exact key match i.e. if a key is present in packet
   it will match only tunnel with the same key; if it is not present,
   it will match only keyless tunnel.

   All keysless packets, if not matched configured keyless tunnels
   will match fallback tunnel.
 */

Al Viro's avatar
Al Viro committed
155
#define HASH(addr) (((__force u32)addr^((__force u32)addr>>4))&0xF)
Linus Torvalds's avatar
Linus Torvalds committed
156

157
158
159
160
#define tunnels_r_l	tunnels[3]
#define tunnels_r	tunnels[2]
#define tunnels_l	tunnels[1]
#define tunnels_wc	tunnels[0]
161
/*
Eric Dumazet's avatar
Eric Dumazet committed
162
 * Locking : hash tables are protected by RCU and RTNL
163
 */
Linus Torvalds's avatar
Linus Torvalds committed
164

165
166
#define for_each_ip_tunnel_rcu(start) \
	for (t = rcu_dereference(start); t; t = rcu_dereference(t->next))
Linus Torvalds's avatar
Linus Torvalds committed
167

Eric Dumazet's avatar
Eric Dumazet committed
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
/* often modified stats are per cpu, other are shared (netdev->stats) */
struct pcpu_tstats {
	unsigned long	rx_packets;
	unsigned long	rx_bytes;
	unsigned long	tx_packets;
	unsigned long	tx_bytes;
};

static struct net_device_stats *ipgre_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;
}

Linus Torvalds's avatar
Linus Torvalds committed
196
197
/* Given src, dst and key, find appropriate for input tunnel. */

198
static struct ip_tunnel * ipgre_tunnel_lookup(struct net_device *dev,
199
200
					      __be32 remote, __be32 local,
					      __be32 key, __be16 gre_proto)
Linus Torvalds's avatar
Linus Torvalds committed
201
{
202
203
	struct net *net = dev_net(dev);
	int link = dev->ifindex;
Eric Dumazet's avatar
Eric Dumazet committed
204
205
	unsigned int h0 = HASH(remote);
	unsigned int h1 = HASH(key);
Timo Teras's avatar
Timo Teras committed
206
	struct ip_tunnel *t, *cand = NULL;
207
	struct ipgre_net *ign = net_generic(net, ipgre_net_id);
208
209
	int dev_type = (gre_proto == htons(ETH_P_TEB)) ?
		       ARPHRD_ETHER : ARPHRD_IPGRE;
Timo Teras's avatar
Timo Teras committed
210
	int score, cand_score = 4;
Linus Torvalds's avatar
Linus Torvalds committed
211

212
	for_each_ip_tunnel_rcu(ign->tunnels_r_l[h0 ^ h1]) {
213
214
215
216
217
218
219
220
221
222
		if (local != t->parms.iph.saddr ||
		    remote != t->parms.iph.daddr ||
		    key != t->parms.i_key ||
		    !(t->dev->flags & IFF_UP))
			continue;

		if (t->dev->type != ARPHRD_IPGRE &&
		    t->dev->type != dev_type)
			continue;

Timo Teras's avatar
Timo Teras committed
223
		score = 0;
224
		if (t->parms.link != link)
Timo Teras's avatar
Timo Teras committed
225
			score |= 1;
226
		if (t->dev->type != dev_type)
Timo Teras's avatar
Timo Teras committed
227
228
			score |= 2;
		if (score == 0)
229
			return t;
Timo Teras's avatar
Timo Teras committed
230
231
232
233
234

		if (score < cand_score) {
			cand = t;
			cand_score = score;
		}
Linus Torvalds's avatar
Linus Torvalds committed
235
	}
236

237
	for_each_ip_tunnel_rcu(ign->tunnels_r[h0 ^ h1]) {
238
239
240
241
242
243
244
245
246
		if (remote != t->parms.iph.daddr ||
		    key != t->parms.i_key ||
		    !(t->dev->flags & IFF_UP))
			continue;

		if (t->dev->type != ARPHRD_IPGRE &&
		    t->dev->type != dev_type)
			continue;

Timo Teras's avatar
Timo Teras committed
247
		score = 0;
248
		if (t->parms.link != link)
Timo Teras's avatar
Timo Teras committed
249
			score |= 1;
250
		if (t->dev->type != dev_type)
Timo Teras's avatar
Timo Teras committed
251
252
			score |= 2;
		if (score == 0)
253
			return t;
Timo Teras's avatar
Timo Teras committed
254
255
256
257
258

		if (score < cand_score) {
			cand = t;
			cand_score = score;
		}
Linus Torvalds's avatar
Linus Torvalds committed
259
	}
260

261
	for_each_ip_tunnel_rcu(ign->tunnels_l[h1]) {
262
263
264
265
266
267
268
269
270
271
272
		if ((local != t->parms.iph.saddr &&
		     (local != t->parms.iph.daddr ||
		      !ipv4_is_multicast(local))) ||
		    key != t->parms.i_key ||
		    !(t->dev->flags & IFF_UP))
			continue;

		if (t->dev->type != ARPHRD_IPGRE &&
		    t->dev->type != dev_type)
			continue;

Timo Teras's avatar
Timo Teras committed
273
		score = 0;
274
		if (t->parms.link != link)
Timo Teras's avatar
Timo Teras committed
275
			score |= 1;
276
		if (t->dev->type != dev_type)
Timo Teras's avatar
Timo Teras committed
277
278
			score |= 2;
		if (score == 0)
279
			return t;
Timo Teras's avatar
Timo Teras committed
280
281
282
283
284

		if (score < cand_score) {
			cand = t;
			cand_score = score;
		}
Linus Torvalds's avatar
Linus Torvalds committed
285
	}
286

287
	for_each_ip_tunnel_rcu(ign->tunnels_wc[h1]) {
288
289
290
291
292
293
294
295
		if (t->parms.i_key != key ||
		    !(t->dev->flags & IFF_UP))
			continue;

		if (t->dev->type != ARPHRD_IPGRE &&
		    t->dev->type != dev_type)
			continue;

Timo Teras's avatar
Timo Teras committed
296
		score = 0;
297
		if (t->parms.link != link)
Timo Teras's avatar
Timo Teras committed
298
			score |= 1;
299
		if (t->dev->type != dev_type)
Timo Teras's avatar
Timo Teras committed
300
301
			score |= 2;
		if (score == 0)
302
			return t;
Timo Teras's avatar
Timo Teras committed
303
304
305
306
307

		if (score < cand_score) {
			cand = t;
			cand_score = score;
		}
Linus Torvalds's avatar
Linus Torvalds committed
308
309
	}

Timo Teras's avatar
Timo Teras committed
310
311
	if (cand != NULL)
		return cand;
312

313
314
315
	dev = ign->fb_tunnel_dev;
	if (dev->flags & IFF_UP)
		return netdev_priv(dev);
316

Linus Torvalds's avatar
Linus Torvalds committed
317
318
319
	return NULL;
}

Eric Dumazet's avatar
Eric Dumazet committed
320
static struct ip_tunnel __rcu **__ipgre_bucket(struct ipgre_net *ign,
321
		struct ip_tunnel_parm *parms)
Linus Torvalds's avatar
Linus Torvalds committed
322
{
323
324
325
	__be32 remote = parms->iph.daddr;
	__be32 local = parms->iph.saddr;
	__be32 key = parms->i_key;
Eric Dumazet's avatar
Eric Dumazet committed
326
	unsigned int h = HASH(key);
Linus Torvalds's avatar
Linus Torvalds committed
327
328
329
330
	int prio = 0;

	if (local)
		prio |= 1;
331
	if (remote && !ipv4_is_multicast(remote)) {
Linus Torvalds's avatar
Linus Torvalds committed
332
333
334
335
		prio |= 2;
		h ^= HASH(remote);
	}

336
	return &ign->tunnels[prio][h];
Linus Torvalds's avatar
Linus Torvalds committed
337
338
}

Eric Dumazet's avatar
Eric Dumazet committed
339
static inline struct ip_tunnel __rcu **ipgre_bucket(struct ipgre_net *ign,
340
		struct ip_tunnel *t)
341
{
342
	return __ipgre_bucket(ign, &t->parms);
343
344
}

345
static void ipgre_tunnel_link(struct ipgre_net *ign, struct ip_tunnel *t)
Linus Torvalds's avatar
Linus Torvalds committed
346
{
Eric Dumazet's avatar
Eric Dumazet committed
347
	struct ip_tunnel __rcu **tp = ipgre_bucket(ign, t);
Linus Torvalds's avatar
Linus Torvalds committed
348

Eric Dumazet's avatar
Eric Dumazet committed
349
	rcu_assign_pointer(t->next, rtnl_dereference(*tp));
350
	rcu_assign_pointer(*tp, t);
Linus Torvalds's avatar
Linus Torvalds committed
351
352
}

353
static void ipgre_tunnel_unlink(struct ipgre_net *ign, struct ip_tunnel *t)
Linus Torvalds's avatar
Linus Torvalds committed
354
{
Eric Dumazet's avatar
Eric Dumazet committed
355
356
357
358
359
360
361
362
	struct ip_tunnel __rcu **tp;
	struct ip_tunnel *iter;

	for (tp = ipgre_bucket(ign, t);
	     (iter = rtnl_dereference(*tp)) != NULL;
	     tp = &iter->next) {
		if (t == iter) {
			rcu_assign_pointer(*tp, t->next);
Linus Torvalds's avatar
Linus Torvalds committed
363
364
365
366
367
			break;
		}
	}
}

368
369
370
static struct ip_tunnel *ipgre_tunnel_find(struct net *net,
					   struct ip_tunnel_parm *parms,
					   int type)
Linus Torvalds's avatar
Linus Torvalds committed
371
{
Al Viro's avatar
Al Viro committed
372
373
374
	__be32 remote = parms->iph.daddr;
	__be32 local = parms->iph.saddr;
	__be32 key = parms->i_key;
375
	int link = parms->link;
Eric Dumazet's avatar
Eric Dumazet committed
376
377
	struct ip_tunnel *t;
	struct ip_tunnel __rcu **tp;
378
379
	struct ipgre_net *ign = net_generic(net, ipgre_net_id);

Eric Dumazet's avatar
Eric Dumazet committed
380
381
382
	for (tp = __ipgre_bucket(ign, parms);
	     (t = rtnl_dereference(*tp)) != NULL;
	     tp = &t->next)
383
384
385
		if (local == t->parms.iph.saddr &&
		    remote == t->parms.iph.daddr &&
		    key == t->parms.i_key &&
386
		    link == t->parms.link &&
387
388
389
390
391
392
		    type == t->dev->type)
			break;

	return t;
}

Eric Dumazet's avatar
Eric Dumazet committed
393
static struct ip_tunnel *ipgre_tunnel_locate(struct net *net,
394
395
396
		struct ip_tunnel_parm *parms, int create)
{
	struct ip_tunnel *t, *nt;
Linus Torvalds's avatar
Linus Torvalds committed
397
398
	struct net_device *dev;
	char name[IFNAMSIZ];
399
	struct ipgre_net *ign = net_generic(net, ipgre_net_id);
Linus Torvalds's avatar
Linus Torvalds committed
400

401
402
403
	t = ipgre_tunnel_find(net, parms, ARPHRD_IPGRE);
	if (t || !create)
		return t;
Linus Torvalds's avatar
Linus Torvalds committed
404
405
406

	if (parms->name[0])
		strlcpy(name, parms->name, IFNAMSIZ);
407
	else
stephen hemminger's avatar
stephen hemminger committed
408
		strcpy(name, "gre%d");
Linus Torvalds's avatar
Linus Torvalds committed
409
410
411

	dev = alloc_netdev(sizeof(*t), name, ipgre_tunnel_setup);
	if (!dev)
stephen hemminger's avatar
stephen hemminger committed
412
		return NULL;
Linus Torvalds's avatar
Linus Torvalds committed
413

414
415
	dev_net_set(dev, net);

416
417
418
419
420
	if (strchr(name, '%')) {
		if (dev_alloc_name(dev, name) < 0)
			goto failed_free;
	}

421
	nt = netdev_priv(dev);
Linus Torvalds's avatar
Linus Torvalds committed
422
	nt->parms = *parms;
Herbert Xu's avatar
Herbert Xu committed
423
	dev->rtnl_link_ops = &ipgre_link_ops;
Linus Torvalds's avatar
Linus Torvalds committed
424

425
426
	dev->mtu = ipgre_tunnel_bind_dev(dev);

427
428
	if (register_netdevice(dev) < 0)
		goto failed_free;
Linus Torvalds's avatar
Linus Torvalds committed
429
430

	dev_hold(dev);
431
	ipgre_tunnel_link(ign, nt);
Linus Torvalds's avatar
Linus Torvalds committed
432
433
	return nt;

434
435
failed_free:
	free_netdev(dev);
Linus Torvalds's avatar
Linus Torvalds committed
436
437
438
439
440
	return NULL;
}

static void ipgre_tunnel_uninit(struct net_device *dev)
{
441
442
443
444
	struct net *net = dev_net(dev);
	struct ipgre_net *ign = net_generic(net, ipgre_net_id);

	ipgre_tunnel_unlink(ign, netdev_priv(dev));
Linus Torvalds's avatar
Linus Torvalds committed
445
446
447
448
449
450
451
	dev_put(dev);
}


static void ipgre_err(struct sk_buff *skb, u32 info)
{

452
/* All the routers (except for Linux) return only
Linus Torvalds's avatar
Linus Torvalds committed
453
454
455
456
457
458
459
460
461
462
463
464
   8 bytes of packet payload. It means, that precise relaying of
   ICMP in the real Internet is absolutely infeasible.

   Moreover, Cisco "wise men" put GRE key to the third word
   in GRE header. It makes impossible maintaining even soft state for keyed
   GRE tunnels with enabled checksum. Tell them "thank you".

   Well, I wonder, rfc1812 was written by Cisco employee,
   what the hell these idiots break standrads established
   by themself???
 */

465
	struct iphdr *iph = (struct iphdr *)skb->data;
Al Viro's avatar
Al Viro committed
466
	__be16	     *p = (__be16*)(skb->data+(iph->ihl<<2));
Linus Torvalds's avatar
Linus Torvalds committed
467
	int grehlen = (iph->ihl<<2) + 4;
468
469
	const int type = icmp_hdr(skb)->type;
	const int code = icmp_hdr(skb)->code;
Linus Torvalds's avatar
Linus Torvalds committed
470
	struct ip_tunnel *t;
Al Viro's avatar
Al Viro committed
471
	__be16 flags;
Linus Torvalds's avatar
Linus Torvalds committed
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515

	flags = p[0];
	if (flags&(GRE_CSUM|GRE_KEY|GRE_SEQ|GRE_ROUTING|GRE_VERSION)) {
		if (flags&(GRE_VERSION|GRE_ROUTING))
			return;
		if (flags&GRE_KEY) {
			grehlen += 4;
			if (flags&GRE_CSUM)
				grehlen += 4;
		}
	}

	/* If only 8 bytes returned, keyed message will be dropped here */
	if (skb_headlen(skb) < grehlen)
		return;

	switch (type) {
	default:
	case ICMP_PARAMETERPROB:
		return;

	case ICMP_DEST_UNREACH:
		switch (code) {
		case ICMP_SR_FAILED:
		case ICMP_PORT_UNREACH:
			/* Impossible event. */
			return;
		case ICMP_FRAG_NEEDED:
			/* Soft state for pmtu is maintained by IP core. */
			return;
		default:
			/* All others are translated to HOST_UNREACH.
			   rfc2003 contains "deep thoughts" about NET_UNREACH,
			   I believe they are just ether pollution. --ANK
			 */
			break;
		}
		break;
	case ICMP_TIME_EXCEEDED:
		if (code != ICMP_EXC_TTL)
			return;
		break;
	}

516
	rcu_read_lock();
517
	t = ipgre_tunnel_lookup(skb->dev, iph->daddr, iph->saddr,
518
519
520
				flags & GRE_KEY ?
				*(((__be32 *)p) + (grehlen / 4) - 1) : 0,
				p[1]);
521
522
	if (t == NULL || t->parms.iph.daddr == 0 ||
	    ipv4_is_multicast(t->parms.iph.daddr))
Linus Torvalds's avatar
Linus Torvalds committed
523
524
525
526
527
		goto out;

	if (t->parms.iph.ttl == 0 && type == ICMP_TIME_EXCEEDED)
		goto out;

528
	if (time_before(jiffies, t->err_time + IPTUNNEL_ERR_TIMEO))
Linus Torvalds's avatar
Linus Torvalds committed
529
530
531
532
533
		t->err_count++;
	else
		t->err_count = 1;
	t->err_time = jiffies;
out:
534
	rcu_read_unlock();
Linus Torvalds's avatar
Linus Torvalds committed
535
536
537
538
539
540
}

static inline void ipgre_ecn_decapsulate(struct iphdr *iph, struct sk_buff *skb)
{
	if (INET_ECN_is_ce(iph->tos)) {
		if (skb->protocol == htons(ETH_P_IP)) {
541
			IP_ECN_set_ce(ip_hdr(skb));
Linus Torvalds's avatar
Linus Torvalds committed
542
		} else if (skb->protocol == htons(ETH_P_IPV6)) {
543
			IP6_ECN_set_ce(ipv6_hdr(skb));
Linus Torvalds's avatar
Linus Torvalds committed
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
		}
	}
}

static inline u8
ipgre_ecn_encapsulate(u8 tos, struct iphdr *old_iph, struct sk_buff *skb)
{
	u8 inner = 0;
	if (skb->protocol == htons(ETH_P_IP))
		inner = old_iph->tos;
	else if (skb->protocol == htons(ETH_P_IPV6))
		inner = ipv6_get_dsfield((struct ipv6hdr *)old_iph);
	return INET_ECN_encapsulate(tos, inner);
}

static int ipgre_rcv(struct sk_buff *skb)
{
	struct iphdr *iph;
	u8     *h;
Al Viro's avatar
Al Viro committed
563
	__be16    flags;
564
	__sum16   csum = 0;
Al Viro's avatar
Al Viro committed
565
	__be32 key = 0;
Linus Torvalds's avatar
Linus Torvalds committed
566
567
568
	u32    seqno = 0;
	struct ip_tunnel *tunnel;
	int    offset = 4;
569
	__be16 gre_proto;
Linus Torvalds's avatar
Linus Torvalds committed
570
571
572
573

	if (!pskb_may_pull(skb, 16))
		goto drop_nolock;

574
	iph = ip_hdr(skb);
Linus Torvalds's avatar
Linus Torvalds committed
575
	h = skb->data;
Al Viro's avatar
Al Viro committed
576
	flags = *(__be16*)h;
Linus Torvalds's avatar
Linus Torvalds committed
577
578
579
580
581
582
583
584
585

	if (flags&(GRE_CSUM|GRE_KEY|GRE_ROUTING|GRE_SEQ|GRE_VERSION)) {
		/* - Version must be 0.
		   - We do not support routing headers.
		 */
		if (flags&(GRE_VERSION|GRE_ROUTING))
			goto drop_nolock;

		if (flags&GRE_CSUM) {
586
			switch (skb->ip_summed) {
587
			case CHECKSUM_COMPLETE:
588
				csum = csum_fold(skb->csum);
589
590
591
592
593
594
				if (!csum)
					break;
				/* fall through */
			case CHECKSUM_NONE:
				skb->csum = 0;
				csum = __skb_checksum_complete(skb);
595
				skb->ip_summed = CHECKSUM_COMPLETE;
Linus Torvalds's avatar
Linus Torvalds committed
596
597
598
599
			}
			offset += 4;
		}
		if (flags&GRE_KEY) {
Al Viro's avatar
Al Viro committed
600
			key = *(__be32*)(h + offset);
Linus Torvalds's avatar
Linus Torvalds committed
601
602
603
			offset += 4;
		}
		if (flags&GRE_SEQ) {
Al Viro's avatar
Al Viro committed
604
			seqno = ntohl(*(__be32*)(h + offset));
Linus Torvalds's avatar
Linus Torvalds committed
605
606
607
608
			offset += 4;
		}
	}

609
610
	gre_proto = *(__be16 *)(h + 2);

611
	rcu_read_lock();
612
	if ((tunnel = ipgre_tunnel_lookup(skb->dev,
613
614
					  iph->saddr, iph->daddr, key,
					  gre_proto))) {
Eric Dumazet's avatar
Eric Dumazet committed
615
		struct pcpu_tstats *tstats;
616

Linus Torvalds's avatar
Linus Torvalds committed
617
618
		secpath_reset(skb);

619
		skb->protocol = gre_proto;
Linus Torvalds's avatar
Linus Torvalds committed
620
621
622
623
		/* WCCP version 1 and 2 protocol decoding.
		 * - Change protocol to IP
		 * - When dealing with WCCPv2, Skip extra 4 bytes in GRE header
		 */
624
		if (flags == 0 && gre_proto == htons(ETH_P_WCCP)) {
625
			skb->protocol = htons(ETH_P_IP);
626
			if ((*(h + offset) & 0xF0) != 0x40)
Linus Torvalds's avatar
Linus Torvalds committed
627
628
629
				offset += 4;
		}

630
		skb->mac_header = skb->network_header;
631
		__pskb_pull(skb, offset);
632
		skb_postpull_rcsum(skb, skb_transport_header(skb), offset);
Linus Torvalds's avatar
Linus Torvalds committed
633
634
		skb->pkt_type = PACKET_HOST;
#ifdef CONFIG_NET_IPGRE_BROADCAST
635
		if (ipv4_is_multicast(iph->daddr)) {
Linus Torvalds's avatar
Linus Torvalds committed
636
			/* Looped back packet, drop it! */
637
			if (rt_is_output_route(skb_rtable(skb)))
Linus Torvalds's avatar
Linus Torvalds committed
638
				goto drop;
Eric Dumazet's avatar
Eric Dumazet committed
639
			tunnel->dev->stats.multicast++;
Linus Torvalds's avatar
Linus Torvalds committed
640
641
642
643
644
645
			skb->pkt_type = PACKET_BROADCAST;
		}
#endif

		if (((flags&GRE_CSUM) && csum) ||
		    (!(flags&GRE_CSUM) && tunnel->parms.i_flags&GRE_CSUM)) {
Eric Dumazet's avatar
Eric Dumazet committed
646
647
			tunnel->dev->stats.rx_crc_errors++;
			tunnel->dev->stats.rx_errors++;
Linus Torvalds's avatar
Linus Torvalds committed
648
649
650
651
652
			goto drop;
		}
		if (tunnel->parms.i_flags&GRE_SEQ) {
			if (!(flags&GRE_SEQ) ||
			    (tunnel->i_seqno && (s32)(seqno - tunnel->i_seqno) < 0)) {
Eric Dumazet's avatar
Eric Dumazet committed
653
654
				tunnel->dev->stats.rx_fifo_errors++;
				tunnel->dev->stats.rx_errors++;
Linus Torvalds's avatar
Linus Torvalds committed
655
656
657
658
				goto drop;
			}
			tunnel->i_seqno = seqno + 1;
		}
659
660
661
662

		/* Warning: All skb pointers will be invalidated! */
		if (tunnel->dev->type == ARPHRD_ETHER) {
			if (!pskb_may_pull(skb, ETH_HLEN)) {
Eric Dumazet's avatar
Eric Dumazet committed
663
664
				tunnel->dev->stats.rx_length_errors++;
				tunnel->dev->stats.rx_errors++;
665
666
667
668
669
670
671
672
				goto drop;
			}

			iph = ip_hdr(skb);
			skb->protocol = eth_type_trans(skb, tunnel->dev);
			skb_postpull_rcsum(skb, eth_hdr(skb), ETH_HLEN);
		}

Eric Dumazet's avatar
Eric Dumazet committed
673
674
675
676
677
		tstats = this_cpu_ptr(tunnel->dev->tstats);
		tstats->rx_packets++;
		tstats->rx_bytes += skb->len;

		__skb_tunnel_rx(skb, tunnel->dev);
678
679

		skb_reset_network_header(skb);
Linus Torvalds's avatar
Linus Torvalds committed
680
		ipgre_ecn_decapsulate(iph, skb);
681

682
		netif_rx(skb);
Eric Dumazet's avatar
Eric Dumazet committed
683

684
		rcu_read_unlock();
Eric Dumazet's avatar
Eric Dumazet committed
685
		return 0;
Linus Torvalds's avatar
Linus Torvalds committed
686
	}
687
	icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0);
Linus Torvalds's avatar
Linus Torvalds committed
688
689

drop:
690
	rcu_read_unlock();
Linus Torvalds's avatar
Linus Torvalds committed
691
692
drop_nolock:
	kfree_skb(skb);
Eric Dumazet's avatar
Eric Dumazet committed
693
	return 0;
Linus Torvalds's avatar
Linus Torvalds committed
694
695
}

696
static netdev_tx_t ipgre_tunnel_xmit(struct sk_buff *skb, struct net_device *dev)
Linus Torvalds's avatar
Linus Torvalds committed
697
{
698
	struct ip_tunnel *tunnel = netdev_priv(dev);
Eric Dumazet's avatar
Eric Dumazet committed
699
	struct pcpu_tstats *tstats;
700
	struct iphdr  *old_iph = ip_hdr(skb);
Linus Torvalds's avatar
Linus Torvalds committed
701
702
	struct iphdr  *tiph;
	u8     tos;
Al Viro's avatar
Al Viro committed
703
	__be16 df;
Linus Torvalds's avatar
Linus Torvalds committed
704
	struct rtable *rt;     			/* Route to the other host */
Eric Dumazet's avatar
Eric Dumazet committed
705
	struct net_device *tdev;		/* Device to other host */
Linus Torvalds's avatar
Linus Torvalds committed
706
	struct iphdr  *iph;			/* Our new IP header */
707
	unsigned int max_headroom;		/* The extra header space needed */
Linus Torvalds's avatar
Linus Torvalds committed
708
	int    gre_hlen;
Al Viro's avatar
Al Viro committed
709
	__be32 dst;
Linus Torvalds's avatar
Linus Torvalds committed
710
711
	int    mtu;

712
713
714
715
	if (dev->type == ARPHRD_ETHER)
		IPCB(skb)->flags = 0;

	if (dev->header_ops && dev->type == ARPHRD_IPGRE) {
Linus Torvalds's avatar
Linus Torvalds committed
716
		gre_hlen = 0;
717
		tiph = (struct iphdr *)skb->data;
Linus Torvalds's avatar
Linus Torvalds committed
718
719
720
721
722
723
724
725
	} else {
		gre_hlen = tunnel->hlen;
		tiph = &tunnel->parms.iph;
	}

	if ((dst = tiph->daddr) == 0) {
		/* NBMA tunnel */

Eric Dumazet's avatar
Eric Dumazet committed
726
		if (skb_dst(skb) == NULL) {
Eric Dumazet's avatar
Eric Dumazet committed
727
			dev->stats.tx_fifo_errors++;
Linus Torvalds's avatar
Linus Torvalds committed
728
729
730
731
			goto tx_error;
		}

		if (skb->protocol == htons(ETH_P_IP)) {
Eric Dumazet's avatar
Eric Dumazet committed
732
			rt = skb_rtable(skb);
Linus Torvalds's avatar
Linus Torvalds committed
733
734
735
			if ((dst = rt->rt_gateway) == 0)
				goto tx_error_icmp;
		}
736
#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
Linus Torvalds's avatar
Linus Torvalds committed
737
738
739
		else if (skb->protocol == htons(ETH_P_IPV6)) {
			struct in6_addr *addr6;
			int addr_type;
Eric Dumazet's avatar
Eric Dumazet committed
740
			struct neighbour *neigh = skb_dst(skb)->neighbour;
Linus Torvalds's avatar
Linus Torvalds committed
741
742
743
744

			if (neigh == NULL)
				goto tx_error;

745
			addr6 = (struct in6_addr *)&neigh->primary_key;
Linus Torvalds's avatar
Linus Torvalds committed
746
747
748
			addr_type = ipv6_addr_type(addr6);

			if (addr_type == IPV6_ADDR_ANY) {
749
				addr6 = &ipv6_hdr(skb)->daddr;
Linus Torvalds's avatar
Linus Torvalds committed
750
751
752
753
754
755
756
757
758
759
760
761
762
763
				addr_type = ipv6_addr_type(addr6);
			}

			if ((addr_type & IPV6_ADDR_COMPATv4) == 0)
				goto tx_error_icmp;

			dst = addr6->s6_addr32[3];
		}
#endif
		else
			goto tx_error;
	}

	tos = tiph->tos;
764
765
	if (tos == 1) {
		tos = 0;
Linus Torvalds's avatar
Linus Torvalds committed
766
767
		if (skb->protocol == htons(ETH_P_IP))
			tos = old_iph->tos;
768
769
		else if (skb->protocol == htons(ETH_P_IPV6))
			tos = ipv6_get_dsfield((struct ipv6hdr *)old_iph);
Linus Torvalds's avatar
Linus Torvalds committed
770
771
	}

772
773
774
775
776
777
	rt = ip_route_output_gre(dev_net(dev), dst, tiph->saddr,
				 tunnel->parms.o_key, RT_TOS(tos),
				 tunnel->parms.link);
	if (IS_ERR(rt)) {
		dev->stats.tx_carrier_errors++;
		goto tx_error;
Linus Torvalds's avatar
Linus Torvalds committed
778
	}
779
	tdev = rt->dst.dev;
Linus Torvalds's avatar
Linus Torvalds committed
780
781
782

	if (tdev == dev) {
		ip_rt_put(rt);
Eric Dumazet's avatar
Eric Dumazet committed
783
		dev->stats.collisions++;
Linus Torvalds's avatar
Linus Torvalds committed
784
785
786
787
788
		goto tx_error;
	}

	df = tiph->frag_off;
	if (df)
789
		mtu = dst_mtu(&rt->dst) - dev->hard_header_len - tunnel->hlen;
Linus Torvalds's avatar
Linus Torvalds committed
790
	else
Eric Dumazet's avatar
Eric Dumazet committed
791
		mtu = skb_dst(skb) ? dst_mtu(skb_dst(skb)) : dev->mtu;
Linus Torvalds's avatar
Linus Torvalds committed
792

Eric Dumazet's avatar
Eric Dumazet committed
793
794
	if (skb_dst(skb))
		skb_dst(skb)->ops->update_pmtu(skb_dst(skb), mtu);
Linus Torvalds's avatar
Linus Torvalds committed
795
796
797
798
799
800
801
802
803
804
805

	if (skb->protocol == htons(ETH_P_IP)) {
		df |= (old_iph->frag_off&htons(IP_DF));

		if ((old_iph->frag_off&htons(IP_DF)) &&
		    mtu < ntohs(old_iph->tot_len)) {
			icmp_send(skb, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED, htonl(mtu));
			ip_rt_put(rt);
			goto tx_error;
		}
	}
806
#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
Linus Torvalds's avatar
Linus Torvalds committed
807
	else if (skb->protocol == htons(ETH_P_IPV6)) {
Eric Dumazet's avatar
Eric Dumazet committed
808
		struct rt6_info *rt6 = (struct rt6_info *)skb_dst(skb);
Linus Torvalds's avatar
Linus Torvalds committed
809

Eric Dumazet's avatar
Eric Dumazet committed
810
		if (rt6 && mtu < dst_mtu(skb_dst(skb)) && mtu >= IPV6_MIN_MTU) {
811
812
			if ((tunnel->parms.iph.daddr &&
			     !ipv4_is_multicast(tunnel->parms.iph.daddr)) ||
Linus Torvalds's avatar
Linus Torvalds committed
813
814
			    rt6->rt6i_dst.plen == 128) {
				rt6->rt6i_flags |= RTF_MODIFIED;
815
				dst_metric_set(skb_dst(skb), RTAX_MTU, mtu);
Linus Torvalds's avatar
Linus Torvalds committed
816
817
818
819
			}
		}

		if (mtu >= IPV6_MIN_MTU && mtu < skb->len - tunnel->hlen + gre_hlen) {
820
			icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu);
Linus Torvalds's avatar
Linus Torvalds committed
821
822
823
824
825
826
827
			ip_rt_put(rt);
			goto tx_error;
		}
	}
#endif

	if (tunnel->err_count > 0) {
828
829
		if (time_before(jiffies,
				tunnel->err_time + IPTUNNEL_ERR_TIMEO)) {
Linus Torvalds's avatar
Linus Torvalds committed
830
831
832
833
834
835
836
			tunnel->err_count--;

			dst_link_failure(skb);
		} else
			tunnel->err_count = 0;
	}

837
	max_headroom = LL_RESERVED_SPACE(tdev) + gre_hlen + rt->dst.header_len;
Linus Torvalds's avatar
Linus Torvalds committed
838

839
840
	if (skb_headroom(skb) < max_headroom || skb_shared(skb)||
	    (skb_cloned(skb) && !skb_clone_writable(skb, 0))) {
Linus Torvalds's avatar
Linus Torvalds committed
841
		struct sk_buff *new_skb = skb_realloc_headroom(skb, max_headroom);
842
843
		if (max_headroom > dev->needed_headroom)
			dev->needed_headroom = max_headroom;
Linus Torvalds's avatar
Linus Torvalds committed
844
845
		if (!new_skb) {
			ip_rt_put(rt);
Eric Dumazet's avatar
Eric Dumazet committed
846
			dev->stats.tx_dropped++;
Linus Torvalds's avatar
Linus Torvalds committed
847
			dev_kfree_skb(skb);
848
			return NETDEV_TX_OK;
Linus Torvalds's avatar
Linus Torvalds committed
849
850
851
852
853
		}
		if (skb->sk)
			skb_set_owner_w(new_skb, skb->sk);
		dev_kfree_skb(skb);
		skb = new_skb;
854
		old_iph = ip_hdr(skb);
Linus Torvalds's avatar
Linus Torvalds committed
855
856
	}

857
	skb_reset_transport_header(skb);
858
859
	skb_push(skb, gre_hlen);
	skb_reset_network_header(skb);
Linus Torvalds's avatar
Linus Torvalds committed
860
	memset(&(IPCB(skb)->opt), 0, sizeof(IPCB(skb)->opt));
861
862
	IPCB(skb)->flags &= ~(IPSKB_XFRM_TUNNEL_SIZE | IPSKB_XFRM_TRANSFORMED |
			      IPSKB_REROUTED);
Eric Dumazet's avatar
Eric Dumazet committed
863
	skb_dst_drop(skb);
864
	skb_dst_set(skb, &rt->dst);
Linus Torvalds's avatar
Linus Torvalds committed
865
866
867
868
869

	/*
	 *	Push down and install the IPIP header.
	 */

870
	iph 			=	ip_hdr(skb);
Linus Torvalds's avatar
Linus Torvalds committed
871
872
873
874
875
876
877
878
879
880
881
	iph->version		=	4;
	iph->ihl		=	sizeof(struct iphdr) >> 2;
	iph->frag_off		=	df;
	iph->protocol		=	IPPROTO_GRE;
	iph->tos		=	ipgre_ecn_encapsulate(tos, old_iph, skb);
	iph->daddr		=	rt->rt_dst;
	iph->saddr		=	rt->rt_src;

	if ((iph->ttl = tiph->ttl) == 0) {
		if (skb->protocol == htons(ETH_P_IP))
			iph->ttl = old_iph->ttl;
882
#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
Linus Torvalds's avatar
Linus Torvalds committed
883
		else if (skb->protocol == htons(ETH_P_IPV6))
884
			iph->ttl = ((struct ipv6hdr *)old_iph)->hop_limit;
Linus Torvalds's avatar
Linus Torvalds committed
885
886
#endif
		else
887
			iph->ttl = ip4_dst_hoplimit(&rt->dst);
Linus Torvalds's avatar
Linus Torvalds committed
888
889
	}

890
891
892
	((__be16 *)(iph + 1))[0] = tunnel->parms.o_flags;
	((__be16 *)(iph + 1))[1] = (dev->type == ARPHRD_ETHER) ?
				   htons(ETH_P_TEB) : skb->protocol;
Linus Torvalds's avatar
Linus Torvalds committed
893
894

	if (tunnel->parms.o_flags&(GRE_KEY|GRE_CSUM|GRE_SEQ)) {
Al Viro's avatar
Al Viro committed
895
		__be32 *ptr = (__be32*)(((u8*)iph) + tunnel->hlen - 4);
Linus Torvalds's avatar
Linus Torvalds committed
896
897
898
899
900
901
902
903
904
905
906
907

		if (tunnel->parms.o_flags&GRE_SEQ) {
			++tunnel->o_seqno;
			*ptr = htonl(tunnel->o_seqno);
			ptr--;
		}
		if (tunnel->parms.o_flags&GRE_KEY) {
			*ptr = tunnel->parms.o_key;
			ptr--;
		}
		if (tunnel->parms.o_flags&GRE_CSUM) {
			*ptr = 0;
908
			*(__sum16*)ptr = ip_compute_csum((void*)(iph+1), skb->len - sizeof(struct iphdr));
Linus Torvalds's avatar
Linus Torvalds committed
909
910
911
912
		}
	}

	nf_reset(skb);
Eric Dumazet's avatar
Eric Dumazet committed
913
914
	tstats = this_cpu_ptr(dev->tstats);
	__IPTUNNEL_XMIT(tstats, &dev->stats);
915
	return NETDEV_TX_OK;
Linus Torvalds's avatar
Linus Torvalds committed
916
917
918
919
920

tx_error_icmp:
	dst_link_failure(skb);

tx_error:
Eric Dumazet's avatar
Eric Dumazet committed
921
	dev->stats.tx_errors++;
Linus Torvalds's avatar
Linus Torvalds committed
922
	dev_kfree_skb(skb);
923
	return NETDEV_TX_OK;
Linus Torvalds's avatar
Linus Torvalds committed
924
925
}

926
static int ipgre_tunnel_bind_dev(struct net_device *dev)
927
928
929
930
931
932
933
934
935
936
937
{
	struct net_device *tdev = NULL;
	struct ip_tunnel *tunnel;
	struct iphdr *iph;
	int hlen = LL_MAX_HEADER;
	int mtu = ETH_DATA_LEN;
	int addend = sizeof(struct iphdr) + 4;

	tunnel = netdev_priv(dev);
	iph = &tunnel->parms.iph;

Herbert Xu's avatar
Herbert Xu committed
938
	/* Guess output device to choose reasonable mtu and needed_headroom */
939
940

	if (iph->daddr) {
941
942
943
944
945
		struct rtable *rt = ip_route_output_gre(dev_net(dev),
							iph->daddr, iph->saddr,
							tunnel->parms.o_key,
							RT_TOS(iph->tos),
							tunnel->parms.link);
Eric Dumazet's avatar
Eric Dumazet committed
946

947
		if (!IS_ERR(rt)) {
948
			tdev = rt->dst.dev;
949
950
			ip_rt_put(rt);
		}
951
952
953

		if (dev->type != ARPHRD_ETHER)
			dev->flags |= IFF_POINTOPOINT;
954
955
956
	}

	if (!tdev && tunnel->parms.link)
957
		tdev = __dev_get_by_index(dev_net(dev), tunnel->parms.link);
958
959

	if (tdev) {
Herbert Xu's avatar
Herbert Xu committed
960
		hlen = tdev->hard_header_len + tdev->needed_headroom;
961
962
963
964
965
966
967
968
969
970
971
972
973
		mtu = tdev->mtu;
	}
	dev->iflink = tunnel->parms.link;

	/* Precalculate GRE options length */
	if (tunnel->parms.o_flags&(GRE_CSUM|GRE_KEY|GRE_SEQ)) {
		if (tunnel->parms.o_flags&GRE_CSUM)
			addend += 4;
		if (tunnel->parms.o_flags&GRE_KEY)
			addend += 4;
		if (tunnel->parms.o_flags&GRE_SEQ)
			addend += 4;
	}
Herbert Xu's avatar
Herbert Xu committed
974
	dev->needed_headroom = addend + hlen;
975
	mtu -= dev->hard_header_len + addend;
976
977
978
979

	if (mtu < 68)
		mtu = 68;

980
981
	tunnel->hlen = addend;

982
	return mtu;
983
984
}

Linus Torvalds's avatar
Linus Torvalds committed
985
986
987
988
989
990
static int
ipgre_tunnel_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd)
{
	int err = 0;
	struct ip_tunnel_parm p;
	struct ip_tunnel *t;
991
992
	struct net *net = dev_net(dev);
	struct ipgre_net *ign = net_generic(net, ipgre_net_id);
Linus Torvalds's avatar
Linus Torvalds committed
993
994
995
996

	switch (cmd) {
	case SIOCGETTUNNEL:
		t = NULL;
997
		if (dev == ign->fb_tunnel_dev) {
Linus Torvalds's avatar
Linus Torvalds committed
998
999
1000
1001
			if (copy_from_user(&p, ifr->ifr_ifru.ifru_data, sizeof(p))) {
				err = -EFAULT;
				break;
			}
1002
			t = ipgre_tunnel_locate(net, &p, 0);
Linus Torvalds's avatar
Linus Torvalds committed
1003
1004
		}
		if (t == NULL)
1005
			t = netdev_priv(dev);
Linus Torvalds's avatar
Linus Torvalds committed
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
		memcpy(&p, &t->parms, sizeof(p));
		if (copy_to_user(ifr->ifr_ifru.ifru_data, &p, sizeof(p)))
			err = -EFAULT;
		break;

	case SIOCADDTUNNEL:
	case SIOCCHGTUNNEL:
		err = -EPERM;
		if (!capable(CAP_NET_ADMIN))
			goto done;

		err = -EFAULT;
		if (copy_from_user(&p, ifr->ifr_ifru.ifru_data, sizeof(p)))
			goto done;

		err = -EINVAL;
		if (p.iph.version != 4 || p.iph.protocol != IPPROTO_GRE ||
		    p.iph.ihl != 5 || (p.iph.frag_off&htons(~IP_DF)) ||
		    ((p.i_flags|p.o_flags)&(GRE_VERSION|GRE_ROUTING)))
			goto done;
		if (p.iph.ttl)
			p.iph.frag_off |= htons(IP_DF);

		if (!(p.i_flags&GRE_KEY))
			p.i_key = 0;
		if (!(p.o_flags&GRE_KEY))
			p.o_key = 0;

1034
		t = ipgre_tunnel_locate(net, &p, cmd == SIOCADDTUNNEL);
Linus Torvalds's avatar
Linus Torvalds committed
1035

1036
		if (dev != ign->fb_tunnel_dev && cmd == SIOCCHGTUNNEL) {
Linus Torvalds's avatar
Linus Torvalds committed
1037
1038
1039
1040
1041
1042
			if (t != NULL) {
				if (t->dev != dev) {
					err = -EEXIST;
					break;
				}
			} else {
Eric Dumazet's avatar
Eric Dumazet committed
1043
				unsigned int nflags = 0;
Linus Torvalds's avatar
Linus Torvalds committed
1044

1045
				t = netdev_priv(dev);
Linus Torvalds's avatar
Linus Torvalds committed
1046

1047
				if (ipv4_is_multicast(p.iph.daddr))
Linus Torvalds's avatar
Linus Torvalds committed
1048
1049
1050
1051
1052
1053
1054
1055
					nflags = IFF_BROADCAST;
				else if (p.iph.daddr)
					nflags = IFF_POINTOPOINT;

				if ((dev->flags^nflags)&(IFF_POINTOPOINT|IFF_BROADCAST)) {
					err = -EINVAL;
					break;
				}
1056
				ipgre_tunnel_unlink(ign, t);
1057
				synchronize_net();
Linus Torvalds's avatar
Linus Torvalds committed
1058
1059
1060
1061
1062
1063
				t->parms.iph.saddr = p.iph.saddr;
				t->parms.iph.daddr = p.iph.daddr;
				t->parms.i_key = p.i_key;
				t->parms.o_key = p.o_key;
				memcpy(dev->dev_addr, &p.iph.saddr, 4);
				memcpy(dev->broadcast, &p.iph.daddr, 4);
1064
				ipgre_tunnel_link(ign, t);
Linus Torvalds's avatar
Linus Torvalds committed
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
				netdev_state_change(dev);
			}
		}

		if (t) {
			err = 0;
			if (cmd == SIOCCHGTUNNEL) {
				t->parms.iph.ttl = p.iph.ttl;
				t->parms.iph.tos = p.iph.tos;
				t->parms.iph.frag_off = p.iph.frag_off;
1075
1076
				if (t->parms.link != p.link) {
					t->parms.link = p.link;
1077
					dev->mtu = ipgre_tunnel_bind_dev(dev);
1078
1079
					netdev_state_change(dev);
				}
Linus Torvalds's avatar
Linus Torvalds committed
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
			}
			if (copy_to_user(ifr->ifr_ifru.ifru_data, &t->parms, sizeof(p)))
				err = -EFAULT;
		} else
			err = (cmd == SIOCADDTUNNEL ? -ENOBUFS : -ENOENT);
		break;

	case SIOCDELTUNNEL:
		err = -EPERM;
		if (!capable(CAP_NET_ADMIN))
			goto done;

1092
		if (dev == ign->fb_tunnel_dev) {
Linus Torvalds's avatar
Linus Torvalds committed
1093
1094
1095
1096
			err = -EFAULT;
			if (copy_from_user(&p, ifr->ifr_ifru.ifru_data, sizeof(p)))
				goto done;
			err = -ENOENT;
1097
			if ((t = ipgre_tunnel_locate(net, &p, 0)) == NULL)
Linus Torvalds's avatar
Linus Torvalds committed
1098
1099
				goto done;
			err = -EPERM;
1100
			if (t == netdev_priv(ign->fb_tunnel_dev))
Linus Torvalds's avatar
Linus Torvalds committed
1101
1102
1103
				goto done;
			dev = t->dev;
		}
1104
1105
		unregister_netdevice(dev);
		err = 0;
Linus Torvalds's avatar
Linus Torvalds committed
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
		break;

	default:
		err = -EINVAL;
	}

done:
	return err;
}

static int ipgre_tunnel_change_mtu(struct net_device *dev, int new_mtu)
{
1118
	struct ip_tunnel *tunnel = netdev_priv(dev);
Herbert Xu's avatar
Herbert Xu committed
1119
1120
	if (new_mtu < 68 ||
	    new_mtu > 0xFFF8 - dev->hard_header_len - tunnel->hlen)
Linus Torvalds's avatar
Linus Torvalds committed
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
		return -EINVAL;
	dev->mtu = new_mtu;
	return 0;
}

/* Nice toy. Unfortunately, useless in real life :-)
   It allows to construct virtual multiprotocol broadcast "LAN"
   over the Internet, provided multicast routing is tuned.


   I have no idea was this bicycle invented before me,
   so that I had to set ARPHRD_IPGRE to a random value.
   I have an impression, that Cisco could make something similar,
   but this feature is apparently missing in IOS<=11.2(8).
1135

Linus Torvalds's avatar
Linus Torvalds committed
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
   I set up 10.66.66/24 and fec0:6666:6666::0/96 as virtual networks
   with broadcast 224.66.66.66. If you have access to mbone, play with me :-)

   ping -t 255 224.66.66.66

   If nobody answers, mbone does not work.

   ip tunnel add Universe mode gre remote 224.66.66.66 local <Your_real_addr> ttl 255
   ip addr add 10.66.66.<somewhat>/24 dev Universe
   ifconfig Universe up
   ifconfig Universe add fe80::<Your_real_addr>/10
   ifconfig Universe add fec0:6666:6666::<Your_real_addr>/96
   ftp 10.66.66.66
   ...
   ftp fec0:6666:6666::193.233.7.65
   ...

 */

1155
1156
static int ipgre_header(struct sk_buff *skb, struct net_device *dev,
			unsigned short type,
Eric Dumazet's avatar
Eric Dumazet committed
1157
			const void *daddr, const void *saddr, unsigned int len)
Linus Torvalds's avatar
Linus Torvalds committed
1158
{
1159
	struct ip_tunnel *t = netdev_priv(dev);
Linus Torvalds's avatar
Linus Torvalds committed
1160
	struct iphdr *iph = (struct iphdr *)skb_push(skb, t->hlen);
Al Viro's avatar
Al Viro committed
1161
	__be16 *p = (__be16*)(iph+1);
Linus Torvalds's avatar
Linus Torvalds committed
1162
1163
1164
1165
1166
1167

	memcpy(iph, &t->parms.iph, sizeof(struct iphdr));
	p[0]		= t->parms.o_flags;
	p[1]		= htons(type);

	/*
1168
	 *	Set the source hardware address.
Linus Torvalds's avatar
Linus Torvalds committed
1169
	 */
1170

Linus Torvalds's avatar
Linus Torvalds committed
1171
1172
	if (saddr)
		memcpy(&iph->saddr, saddr, 4);
1173
	if (daddr)
Linus Torvalds's avatar
Linus Torvalds committed
1174
		memcpy(&iph->daddr, daddr, 4);
1175
	if (iph->daddr)
Linus Torvalds's avatar
Linus Torvalds committed
1176
		return t->hlen;
1177

Linus Torvalds's avatar
Linus Torvalds committed
1178
1179
1180
	return -t->hlen;
}

1181
1182
static int ipgre_header_parse(const struct sk_buff *skb, unsigned char *haddr)
{
1183
	struct iphdr *iph = (struct iphdr *) skb_mac_header(skb);
1184
1185
1186
1187
	memcpy(haddr, &iph->saddr, 4);
	return 4;
}

1188
1189
static const struct header_ops ipgre_header_ops = {
	.create	= ipgre_header,
1190
	.parse	= ipgre_header_parse,
1191
1192
};

1193
#ifdef CONFIG_NET_IPGRE_BROADCAST
Linus Torvalds's avatar
Linus Torvalds committed
1194
1195
static int ipgre_open(struct net_device *dev)
{
1196
	struct ip_tunnel *t = netdev_priv(dev);
Linus Torvalds's avatar
Linus Torvalds committed
1197

1198
	if (ipv4_is_multicast(t->parms.iph.daddr)) {
1199
1200
1201
1202
1203
1204
		struct rtable *rt = ip_route_output_gre(dev_net(dev),
							t->parms.iph.daddr,
							t->parms.iph.saddr,
							t->parms.o_key,
							RT_TOS(t->parms.iph.tos),