Blame view

net/ipv4/ip_gre.c 42.1 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
  /*
e905a9eda   YOSHIFUJI Hideaki   [NET] IPV4: Fix w...
2
   *	Linux NET3:	GRE over IP protocol decoder.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3
4
5
6
7
8
9
10
11
   *
   *	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.
   *
   */
4fc268d24   Randy Dunlap   [PATCH] capable/c...
12
  #include <linux/capability.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
13
14
  #include <linux/module.h>
  #include <linux/types.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
15
  #include <linux/kernel.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
16
  #include <linux/slab.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
17
18
19
20
21
22
23
24
25
26
27
28
29
  #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>
e1a800022   Herbert Xu   gre: Add Transpar...
30
  #include <linux/etherdevice.h>
46f25dffb   Kris Katterjohn   [NET]: Change 150...
31
  #include <linux/if_ether.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
32
33
34
35
36
37
38
39
40
41
42
  
  #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>
59a4c7594   Pavel Emelyanov   [GRE]: Introduce ...
43
44
  #include <net/net_namespace.h>
  #include <net/netns/generic.h>
c19e654dd   Herbert Xu   gre: Add netlink ...
45
  #include <net/rtnetlink.h>
00959ade3   Dmitry Kozlov   PPTP: PPP over IP...
46
  #include <net/gre.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
47

dfd56b8b3   Eric Dumazet   net: use IS_ENABL...
48
  #if IS_ENABLED(CONFIG_IPV6)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
  #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),
6d0722a2c   Eric Dumazet   ip_gre: comments ...
66
     and silently drop packet when it expires. It is a good
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
67
68
     solution, but it supposes maintaing new variable in ALL
     skb, even if no tunneling is used.
6d0722a2c   Eric Dumazet   ip_gre: comments ...
69
70
71
     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
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
72
73
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
  
     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.
   */
c19e654dd   Herbert Xu   gre: Add netlink ...
118
  static struct rtnl_link_ops ipgre_link_ops __read_mostly;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
119
120
  static int ipgre_tunnel_init(struct net_device *dev);
  static void ipgre_tunnel_setup(struct net_device *dev);
42aa91626   Herbert Xu   gre: Move MTU set...
121
  static int ipgre_tunnel_bind_dev(struct net_device *dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
122
123
  
  /* Fallback tunnel: no source, no destination, no key, no options */
eb8ce741a   Pavel Emelyanov   [GRE]: Make tunne...
124
  #define HASH_SIZE  16
f99189b18   Eric Dumazet   netns: net_identi...
125
  static int ipgre_net_id __read_mostly;
59a4c7594   Pavel Emelyanov   [GRE]: Introduce ...
126
  struct ipgre_net {
1507850b4   Eric Dumazet   gre: get rid of i...
127
  	struct ip_tunnel __rcu *tunnels[4][HASH_SIZE];
eb8ce741a   Pavel Emelyanov   [GRE]: Make tunne...
128

7daa00048   Pavel Emelyanov   [GRE]: Make the f...
129
  	struct net_device *fb_tunnel_dev;
59a4c7594   Pavel Emelyanov   [GRE]: Introduce ...
130
  };
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
  /* 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.
   */
d5a0a1e31   Al Viro   [IPV4]: encapsula...
148
  #define HASH(addr) (((__force u32)addr^((__force u32)addr>>4))&0xF)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
149

eb8ce741a   Pavel Emelyanov   [GRE]: Make tunne...
150
151
152
153
  #define tunnels_r_l	tunnels[3]
  #define tunnels_r	tunnels[2]
  #define tunnels_l	tunnels[1]
  #define tunnels_wc	tunnels[0]
8d5b2c084   Eric Dumazet   gre: convert hash...
154
  /*
1507850b4   Eric Dumazet   gre: get rid of i...
155
   * Locking : hash tables are protected by RCU and RTNL
8d5b2c084   Eric Dumazet   gre: convert hash...
156
   */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
157

8d5b2c084   Eric Dumazet   gre: convert hash...
158
159
  #define for_each_ip_tunnel_rcu(start) \
  	for (t = rcu_dereference(start); t; t = rcu_dereference(t->next))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
160

e985aad72   Eric Dumazet   ip_gre: percpu st...
161
162
163
164
165
166
  /* 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;
8ce120f11   Eric Dumazet   net: better pcpu ...
167
  } __attribute__((aligned(4*sizeof(unsigned long))));
e985aad72   Eric Dumazet   ip_gre: percpu st...
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
  
  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;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
188
  /* Given src, dst and key, find appropriate for input tunnel. */
749c10f93   Timo Teras   gre: strict physi...
189
  static struct ip_tunnel * ipgre_tunnel_lookup(struct net_device *dev,
e1a800022   Herbert Xu   gre: Add Transpar...
190
191
  					      __be32 remote, __be32 local,
  					      __be32 key, __be16 gre_proto)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
192
  {
749c10f93   Timo Teras   gre: strict physi...
193
194
  	struct net *net = dev_net(dev);
  	int link = dev->ifindex;
1507850b4   Eric Dumazet   gre: get rid of i...
195
196
  	unsigned int h0 = HASH(remote);
  	unsigned int h1 = HASH(key);
afcf12422   Timo Teras   gre: optimize has...
197
  	struct ip_tunnel *t, *cand = NULL;
7daa00048   Pavel Emelyanov   [GRE]: Make the f...
198
  	struct ipgre_net *ign = net_generic(net, ipgre_net_id);
e1a800022   Herbert Xu   gre: Add Transpar...
199
200
  	int dev_type = (gre_proto == htons(ETH_P_TEB)) ?
  		       ARPHRD_ETHER : ARPHRD_IPGRE;
afcf12422   Timo Teras   gre: optimize has...
201
  	int score, cand_score = 4;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
202

8d5b2c084   Eric Dumazet   gre: convert hash...
203
  	for_each_ip_tunnel_rcu(ign->tunnels_r_l[h0 ^ h1]) {
749c10f93   Timo Teras   gre: strict physi...
204
205
206
207
208
209
210
211
212
  		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;
afcf12422   Timo Teras   gre: optimize has...
213
  		score = 0;
749c10f93   Timo Teras   gre: strict physi...
214
  		if (t->parms.link != link)
afcf12422   Timo Teras   gre: optimize has...
215
  			score |= 1;
749c10f93   Timo Teras   gre: strict physi...
216
  		if (t->dev->type != dev_type)
afcf12422   Timo Teras   gre: optimize has...
217
218
  			score |= 2;
  		if (score == 0)
749c10f93   Timo Teras   gre: strict physi...
219
  			return t;
afcf12422   Timo Teras   gre: optimize has...
220
221
222
223
224
  
  		if (score < cand_score) {
  			cand = t;
  			cand_score = score;
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
225
  	}
e1a800022   Herbert Xu   gre: Add Transpar...
226

8d5b2c084   Eric Dumazet   gre: convert hash...
227
  	for_each_ip_tunnel_rcu(ign->tunnels_r[h0 ^ h1]) {
749c10f93   Timo Teras   gre: strict physi...
228
229
230
231
232
233
234
235
  		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;
afcf12422   Timo Teras   gre: optimize has...
236
  		score = 0;
749c10f93   Timo Teras   gre: strict physi...
237
  		if (t->parms.link != link)
afcf12422   Timo Teras   gre: optimize has...
238
  			score |= 1;
749c10f93   Timo Teras   gre: strict physi...
239
  		if (t->dev->type != dev_type)
afcf12422   Timo Teras   gre: optimize has...
240
241
  			score |= 2;
  		if (score == 0)
749c10f93   Timo Teras   gre: strict physi...
242
  			return t;
afcf12422   Timo Teras   gre: optimize has...
243
244
245
246
247
  
  		if (score < cand_score) {
  			cand = t;
  			cand_score = score;
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
248
  	}
e1a800022   Herbert Xu   gre: Add Transpar...
249

8d5b2c084   Eric Dumazet   gre: convert hash...
250
  	for_each_ip_tunnel_rcu(ign->tunnels_l[h1]) {
749c10f93   Timo Teras   gre: strict physi...
251
252
253
254
255
256
257
258
259
260
  		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;
afcf12422   Timo Teras   gre: optimize has...
261
  		score = 0;
749c10f93   Timo Teras   gre: strict physi...
262
  		if (t->parms.link != link)
afcf12422   Timo Teras   gre: optimize has...
263
  			score |= 1;
749c10f93   Timo Teras   gre: strict physi...
264
  		if (t->dev->type != dev_type)
afcf12422   Timo Teras   gre: optimize has...
265
266
  			score |= 2;
  		if (score == 0)
749c10f93   Timo Teras   gre: strict physi...
267
  			return t;
afcf12422   Timo Teras   gre: optimize has...
268
269
270
271
272
  
  		if (score < cand_score) {
  			cand = t;
  			cand_score = score;
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
273
  	}
e1a800022   Herbert Xu   gre: Add Transpar...
274

8d5b2c084   Eric Dumazet   gre: convert hash...
275
  	for_each_ip_tunnel_rcu(ign->tunnels_wc[h1]) {
749c10f93   Timo Teras   gre: strict physi...
276
277
278
279
280
281
282
  		if (t->parms.i_key != key ||
  		    !(t->dev->flags & IFF_UP))
  			continue;
  
  		if (t->dev->type != ARPHRD_IPGRE &&
  		    t->dev->type != dev_type)
  			continue;
afcf12422   Timo Teras   gre: optimize has...
283
  		score = 0;
749c10f93   Timo Teras   gre: strict physi...
284
  		if (t->parms.link != link)
afcf12422   Timo Teras   gre: optimize has...
285
  			score |= 1;
749c10f93   Timo Teras   gre: strict physi...
286
  		if (t->dev->type != dev_type)
afcf12422   Timo Teras   gre: optimize has...
287
288
  			score |= 2;
  		if (score == 0)
749c10f93   Timo Teras   gre: strict physi...
289
  			return t;
afcf12422   Timo Teras   gre: optimize has...
290
291
292
293
294
  
  		if (score < cand_score) {
  			cand = t;
  			cand_score = score;
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
295
  	}
afcf12422   Timo Teras   gre: optimize has...
296
297
  	if (cand != NULL)
  		return cand;
e1a800022   Herbert Xu   gre: Add Transpar...
298

8d5b2c084   Eric Dumazet   gre: convert hash...
299
300
301
  	dev = ign->fb_tunnel_dev;
  	if (dev->flags & IFF_UP)
  		return netdev_priv(dev);
749c10f93   Timo Teras   gre: strict physi...
302

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
303
304
  	return NULL;
  }
1507850b4   Eric Dumazet   gre: get rid of i...
305
  static struct ip_tunnel __rcu **__ipgre_bucket(struct ipgre_net *ign,
f57e7d5a7   Pavel Emelyanov   [GRE]: Add net/gr...
306
  		struct ip_tunnel_parm *parms)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
307
  {
5056a1ef9   YOSHIFUJI Hideaki   [IPV4] IP_GRE: Un...
308
309
310
  	__be32 remote = parms->iph.daddr;
  	__be32 local = parms->iph.saddr;
  	__be32 key = parms->i_key;
1507850b4   Eric Dumazet   gre: get rid of i...
311
  	unsigned int h = HASH(key);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
312
313
314
315
  	int prio = 0;
  
  	if (local)
  		prio |= 1;
f97c1e0c6   Joe Perches   [IPV4] net/ipv4: ...
316
  	if (remote && !ipv4_is_multicast(remote)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
317
318
319
  		prio |= 2;
  		h ^= HASH(remote);
  	}
eb8ce741a   Pavel Emelyanov   [GRE]: Make tunne...
320
  	return &ign->tunnels[prio][h];
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
321
  }
1507850b4   Eric Dumazet   gre: get rid of i...
322
  static inline struct ip_tunnel __rcu **ipgre_bucket(struct ipgre_net *ign,
f57e7d5a7   Pavel Emelyanov   [GRE]: Add net/gr...
323
  		struct ip_tunnel *t)
5056a1ef9   YOSHIFUJI Hideaki   [IPV4] IP_GRE: Un...
324
  {
f57e7d5a7   Pavel Emelyanov   [GRE]: Add net/gr...
325
  	return __ipgre_bucket(ign, &t->parms);
5056a1ef9   YOSHIFUJI Hideaki   [IPV4] IP_GRE: Un...
326
  }
f57e7d5a7   Pavel Emelyanov   [GRE]: Add net/gr...
327
  static void ipgre_tunnel_link(struct ipgre_net *ign, struct ip_tunnel *t)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
328
  {
1507850b4   Eric Dumazet   gre: get rid of i...
329
  	struct ip_tunnel __rcu **tp = ipgre_bucket(ign, t);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
330

1507850b4   Eric Dumazet   gre: get rid of i...
331
  	rcu_assign_pointer(t->next, rtnl_dereference(*tp));
8d5b2c084   Eric Dumazet   gre: convert hash...
332
  	rcu_assign_pointer(*tp, t);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
333
  }
f57e7d5a7   Pavel Emelyanov   [GRE]: Add net/gr...
334
  static void ipgre_tunnel_unlink(struct ipgre_net *ign, struct ip_tunnel *t)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
335
  {
1507850b4   Eric Dumazet   gre: get rid of i...
336
337
338
339
340
341
342
343
  	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);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
344
345
346
347
  			break;
  		}
  	}
  }
e1a800022   Herbert Xu   gre: Add Transpar...
348
349
350
  static struct ip_tunnel *ipgre_tunnel_find(struct net *net,
  					   struct ip_tunnel_parm *parms,
  					   int type)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
351
  {
d5a0a1e31   Al Viro   [IPV4]: encapsula...
352
353
354
  	__be32 remote = parms->iph.daddr;
  	__be32 local = parms->iph.saddr;
  	__be32 key = parms->i_key;
749c10f93   Timo Teras   gre: strict physi...
355
  	int link = parms->link;
1507850b4   Eric Dumazet   gre: get rid of i...
356
357
  	struct ip_tunnel *t;
  	struct ip_tunnel __rcu **tp;
e1a800022   Herbert Xu   gre: Add Transpar...
358
  	struct ipgre_net *ign = net_generic(net, ipgre_net_id);
1507850b4   Eric Dumazet   gre: get rid of i...
359
360
361
  	for (tp = __ipgre_bucket(ign, parms);
  	     (t = rtnl_dereference(*tp)) != NULL;
  	     tp = &t->next)
e1a800022   Herbert Xu   gre: Add Transpar...
362
363
364
  		if (local == t->parms.iph.saddr &&
  		    remote == t->parms.iph.daddr &&
  		    key == t->parms.i_key &&
749c10f93   Timo Teras   gre: strict physi...
365
  		    link == t->parms.link &&
e1a800022   Herbert Xu   gre: Add Transpar...
366
367
368
369
370
  		    type == t->dev->type)
  			break;
  
  	return t;
  }
1507850b4   Eric Dumazet   gre: get rid of i...
371
  static struct ip_tunnel *ipgre_tunnel_locate(struct net *net,
e1a800022   Herbert Xu   gre: Add Transpar...
372
373
374
  		struct ip_tunnel_parm *parms, int create)
  {
  	struct ip_tunnel *t, *nt;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
375
  	struct net_device *dev;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
376
  	char name[IFNAMSIZ];
f57e7d5a7   Pavel Emelyanov   [GRE]: Add net/gr...
377
  	struct ipgre_net *ign = net_generic(net, ipgre_net_id);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
378

e1a800022   Herbert Xu   gre: Add Transpar...
379
380
381
  	t = ipgre_tunnel_find(net, parms, ARPHRD_IPGRE);
  	if (t || !create)
  		return t;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
382
383
384
  
  	if (parms->name[0])
  		strlcpy(name, parms->name, IFNAMSIZ);
34cc7ba63   Pavel Emelyanov   [IP_TUNNEL]: Don'...
385
  	else
407d6fcbf   stephen hemminger   gre: minor cleanups
386
  		strcpy(name, "gre%d");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
387
388
389
  
  	dev = alloc_netdev(sizeof(*t), name, ipgre_tunnel_setup);
  	if (!dev)
407d6fcbf   stephen hemminger   gre: minor cleanups
390
  		return NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
391

0b67eceb1   Pavel Emelyanov   [GRE]: Allow to c...
392
  	dev_net_set(dev, net);
2941a4863   Patrick McHardy   [NET]: Convert ne...
393
  	nt = netdev_priv(dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
394
  	nt->parms = *parms;
c19e654dd   Herbert Xu   gre: Add netlink ...
395
  	dev->rtnl_link_ops = &ipgre_link_ops;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
396

42aa91626   Herbert Xu   gre: Move MTU set...
397
  	dev->mtu = ipgre_tunnel_bind_dev(dev);
b37d428b2   Pavel Emelyanov   [INET]: Don't cre...
398
399
  	if (register_netdevice(dev) < 0)
  		goto failed_free;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
400

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
401
  	dev_hold(dev);
f57e7d5a7   Pavel Emelyanov   [GRE]: Add net/gr...
402
  	ipgre_tunnel_link(ign, nt);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
403
  	return nt;
b37d428b2   Pavel Emelyanov   [INET]: Don't cre...
404
405
  failed_free:
  	free_netdev(dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
406
407
408
409
410
  	return NULL;
  }
  
  static void ipgre_tunnel_uninit(struct net_device *dev)
  {
f57e7d5a7   Pavel Emelyanov   [GRE]: Add net/gr...
411
412
413
414
  	struct net *net = dev_net(dev);
  	struct ipgre_net *ign = net_generic(net, ipgre_net_id);
  
  	ipgre_tunnel_unlink(ign, netdev_priv(dev));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
415
416
417
418
419
420
  	dev_put(dev);
  }
  
  
  static void ipgre_err(struct sk_buff *skb, u32 info)
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
421

071f92d05   Rami Rosen   net: The world is...
422
  /* All the routers (except for Linux) return only
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
423
424
425
426
427
428
429
430
431
432
433
     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???
   */
b71d1d426   Eric Dumazet   inet: constify ip...
434
  	const struct iphdr *iph = (const struct iphdr *)skb->data;
d5a0a1e31   Al Viro   [IPV4]: encapsula...
435
  	__be16	     *p = (__be16*)(skb->data+(iph->ihl<<2));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
436
  	int grehlen = (iph->ihl<<2) + 4;
88c7664f1   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
437
438
  	const int type = icmp_hdr(skb)->type;
  	const int code = icmp_hdr(skb)->code;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
439
  	struct ip_tunnel *t;
d5a0a1e31   Al Viro   [IPV4]: encapsula...
440
  	__be16 flags;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
  
  	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;
  	}
8d5b2c084   Eric Dumazet   gre: convert hash...
484
  	rcu_read_lock();
749c10f93   Timo Teras   gre: strict physi...
485
  	t = ipgre_tunnel_lookup(skb->dev, iph->daddr, iph->saddr,
e1a800022   Herbert Xu   gre: Add Transpar...
486
487
488
  				flags & GRE_KEY ?
  				*(((__be32 *)p) + (grehlen / 4) - 1) : 0,
  				p[1]);
f97c1e0c6   Joe Perches   [IPV4] net/ipv4: ...
489
490
  	if (t == NULL || t->parms.iph.daddr == 0 ||
  	    ipv4_is_multicast(t->parms.iph.daddr))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
491
492
493
494
  		goto out;
  
  	if (t->parms.iph.ttl == 0 && type == ICMP_TIME_EXCEEDED)
  		goto out;
da6185d87   Wei Yongjun   gre: used time_be...
495
  	if (time_before(jiffies, t->err_time + IPTUNNEL_ERR_TIMEO))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
496
497
498
499
500
  		t->err_count++;
  	else
  		t->err_count = 1;
  	t->err_time = jiffies;
  out:
8d5b2c084   Eric Dumazet   gre: convert hash...
501
  	rcu_read_unlock();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
502
  }
b71d1d426   Eric Dumazet   inet: constify ip...
503
  static inline void ipgre_ecn_decapsulate(const struct iphdr *iph, struct sk_buff *skb)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
504
505
506
  {
  	if (INET_ECN_is_ce(iph->tos)) {
  		if (skb->protocol == htons(ETH_P_IP)) {
eddc9ec53   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
507
  			IP_ECN_set_ce(ip_hdr(skb));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
508
  		} else if (skb->protocol == htons(ETH_P_IPV6)) {
0660e03f6   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
509
  			IP6_ECN_set_ce(ipv6_hdr(skb));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
510
511
512
513
514
  		}
  	}
  }
  
  static inline u8
b71d1d426   Eric Dumazet   inet: constify ip...
515
  ipgre_ecn_encapsulate(u8 tos, const struct iphdr *old_iph, struct sk_buff *skb)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
516
517
518
519
520
  {
  	u8 inner = 0;
  	if (skb->protocol == htons(ETH_P_IP))
  		inner = old_iph->tos;
  	else if (skb->protocol == htons(ETH_P_IPV6))
b71d1d426   Eric Dumazet   inet: constify ip...
521
  		inner = ipv6_get_dsfield((const struct ipv6hdr *)old_iph);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
522
523
524
525
526
  	return INET_ECN_encapsulate(tos, inner);
  }
  
  static int ipgre_rcv(struct sk_buff *skb)
  {
b71d1d426   Eric Dumazet   inet: constify ip...
527
  	const struct iphdr *iph;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
528
  	u8     *h;
d5a0a1e31   Al Viro   [IPV4]: encapsula...
529
  	__be16    flags;
d3bc23e7e   Al Viro   [NET]: Annotate c...
530
  	__sum16   csum = 0;
d5a0a1e31   Al Viro   [IPV4]: encapsula...
531
  	__be32 key = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
532
533
534
  	u32    seqno = 0;
  	struct ip_tunnel *tunnel;
  	int    offset = 4;
e1a800022   Herbert Xu   gre: Add Transpar...
535
  	__be16 gre_proto;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
536
537
538
  
  	if (!pskb_may_pull(skb, 16))
  		goto drop_nolock;
eddc9ec53   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
539
  	iph = ip_hdr(skb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
540
  	h = skb->data;
d5a0a1e31   Al Viro   [IPV4]: encapsula...
541
  	flags = *(__be16*)h;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
542
543
544
545
546
547
548
549
550
  
  	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) {
fb286bb29   Herbert Xu   [NET]: Detect har...
551
  			switch (skb->ip_summed) {
84fa7933a   Patrick McHardy   [NET]: Replace CH...
552
  			case CHECKSUM_COMPLETE:
d3bc23e7e   Al Viro   [NET]: Annotate c...
553
  				csum = csum_fold(skb->csum);
fb286bb29   Herbert Xu   [NET]: Detect har...
554
555
556
557
558
559
  				if (!csum)
  					break;
  				/* fall through */
  			case CHECKSUM_NONE:
  				skb->csum = 0;
  				csum = __skb_checksum_complete(skb);
84fa7933a   Patrick McHardy   [NET]: Replace CH...
560
  				skb->ip_summed = CHECKSUM_COMPLETE;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
561
562
563
564
  			}
  			offset += 4;
  		}
  		if (flags&GRE_KEY) {
d5a0a1e31   Al Viro   [IPV4]: encapsula...
565
  			key = *(__be32*)(h + offset);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
566
567
568
  			offset += 4;
  		}
  		if (flags&GRE_SEQ) {
d5a0a1e31   Al Viro   [IPV4]: encapsula...
569
  			seqno = ntohl(*(__be32*)(h + offset));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
570
571
572
  			offset += 4;
  		}
  	}
e1a800022   Herbert Xu   gre: Add Transpar...
573
  	gre_proto = *(__be16 *)(h + 2);
8d5b2c084   Eric Dumazet   gre: convert hash...
574
  	rcu_read_lock();
749c10f93   Timo Teras   gre: strict physi...
575
  	if ((tunnel = ipgre_tunnel_lookup(skb->dev,
e1a800022   Herbert Xu   gre: Add Transpar...
576
577
  					  iph->saddr, iph->daddr, key,
  					  gre_proto))) {
e985aad72   Eric Dumazet   ip_gre: percpu st...
578
  		struct pcpu_tstats *tstats;
addd68eb6   Pavel Emelyanov   ipgre: Use on-dev...
579

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
580
  		secpath_reset(skb);
e1a800022   Herbert Xu   gre: Add Transpar...
581
  		skb->protocol = gre_proto;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
582
583
584
585
  		/* WCCP version 1 and 2 protocol decoding.
  		 * - Change protocol to IP
  		 * - When dealing with WCCPv2, Skip extra 4 bytes in GRE header
  		 */
e1a800022   Herbert Xu   gre: Add Transpar...
586
  		if (flags == 0 && gre_proto == htons(ETH_P_WCCP)) {
496c98dff   YOSHIFUJI Hideaki   [NET]: Use hton{l...
587
  			skb->protocol = htons(ETH_P_IP);
e905a9eda   YOSHIFUJI Hideaki   [NET] IPV4: Fix w...
588
  			if ((*(h + offset) & 0xF0) != 0x40)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
589
590
  				offset += 4;
  		}
1d0691674   Timo Teras   [IPV4] ip_gre: se...
591
  		skb->mac_header = skb->network_header;
4209fb601   Arnaldo Carvalho de Melo   [SK_BUFF]: Use sk...
592
  		__pskb_pull(skb, offset);
9c70220b7   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
593
  		skb_postpull_rcsum(skb, skb_transport_header(skb), offset);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
594
595
  		skb->pkt_type = PACKET_HOST;
  #ifdef CONFIG_NET_IPGRE_BROADCAST
f97c1e0c6   Joe Perches   [IPV4] net/ipv4: ...
596
  		if (ipv4_is_multicast(iph->daddr)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
597
  			/* Looped back packet, drop it! */
c75379676   David S. Miller   ipv4: Make rt->fl...
598
  			if (rt_is_output_route(skb_rtable(skb)))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
599
  				goto drop;
e985aad72   Eric Dumazet   ip_gre: percpu st...
600
  			tunnel->dev->stats.multicast++;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
601
602
603
604
605
606
  			skb->pkt_type = PACKET_BROADCAST;
  		}
  #endif
  
  		if (((flags&GRE_CSUM) && csum) ||
  		    (!(flags&GRE_CSUM) && tunnel->parms.i_flags&GRE_CSUM)) {
e985aad72   Eric Dumazet   ip_gre: percpu st...
607
608
  			tunnel->dev->stats.rx_crc_errors++;
  			tunnel->dev->stats.rx_errors++;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
609
610
611
612
613
  			goto drop;
  		}
  		if (tunnel->parms.i_flags&GRE_SEQ) {
  			if (!(flags&GRE_SEQ) ||
  			    (tunnel->i_seqno && (s32)(seqno - tunnel->i_seqno) < 0)) {
e985aad72   Eric Dumazet   ip_gre: percpu st...
614
615
  				tunnel->dev->stats.rx_fifo_errors++;
  				tunnel->dev->stats.rx_errors++;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
616
617
618
619
  				goto drop;
  			}
  			tunnel->i_seqno = seqno + 1;
  		}
e1a800022   Herbert Xu   gre: Add Transpar...
620
621
622
623
  
  		/* Warning: All skb pointers will be invalidated! */
  		if (tunnel->dev->type == ARPHRD_ETHER) {
  			if (!pskb_may_pull(skb, ETH_HLEN)) {
e985aad72   Eric Dumazet   ip_gre: percpu st...
624
625
  				tunnel->dev->stats.rx_length_errors++;
  				tunnel->dev->stats.rx_errors++;
e1a800022   Herbert Xu   gre: Add Transpar...
626
627
628
629
630
631
632
  				goto drop;
  			}
  
  			iph = ip_hdr(skb);
  			skb->protocol = eth_type_trans(skb, tunnel->dev);
  			skb_postpull_rcsum(skb, eth_hdr(skb), ETH_HLEN);
  		}
e985aad72   Eric Dumazet   ip_gre: percpu st...
633
634
635
636
637
  		tstats = this_cpu_ptr(tunnel->dev->tstats);
  		tstats->rx_packets++;
  		tstats->rx_bytes += skb->len;
  
  		__skb_tunnel_rx(skb, tunnel->dev);
e1a800022   Herbert Xu   gre: Add Transpar...
638
639
  
  		skb_reset_network_header(skb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
640
  		ipgre_ecn_decapsulate(iph, skb);
e1a800022   Herbert Xu   gre: Add Transpar...
641

caf586e5f   Eric Dumazet   net: add a core n...
642
  		netif_rx(skb);
8990f468a   Eric Dumazet   net: rx_dropped a...
643

8d5b2c084   Eric Dumazet   gre: convert hash...
644
  		rcu_read_unlock();
8990f468a   Eric Dumazet   net: rx_dropped a...
645
  		return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
646
  	}
45af08be6   Herbert Xu   [INET]: Use port ...
647
  	icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
648
649
  
  drop:
8d5b2c084   Eric Dumazet   gre: convert hash...
650
  	rcu_read_unlock();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
651
652
  drop_nolock:
  	kfree_skb(skb);
a02cec215   Eric Dumazet   net: return opera...
653
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
654
  }
6fef4c0c8   Stephen Hemminger   netdev: convert p...
655
  static netdev_tx_t ipgre_tunnel_xmit(struct sk_buff *skb, struct net_device *dev)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
656
  {
2941a4863   Patrick McHardy   [NET]: Convert ne...
657
  	struct ip_tunnel *tunnel = netdev_priv(dev);
e985aad72   Eric Dumazet   ip_gre: percpu st...
658
  	struct pcpu_tstats *tstats;
b71d1d426   Eric Dumazet   inet: constify ip...
659
660
  	const struct iphdr  *old_iph = ip_hdr(skb);
  	const struct iphdr  *tiph;
cbb1e85f9   David S. Miller   ipv4: Kill rt->rt...
661
  	struct flowi4 fl4;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
662
  	u8     tos;
d5a0a1e31   Al Viro   [IPV4]: encapsula...
663
  	__be16 df;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
664
  	struct rtable *rt;     			/* Route to the other host */
1507850b4   Eric Dumazet   gre: get rid of i...
665
  	struct net_device *tdev;		/* Device to other host */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
666
  	struct iphdr  *iph;			/* Our new IP header */
c2636b4d9   Chuck Lever   [NET]: Treat the ...
667
  	unsigned int max_headroom;		/* The extra header space needed */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
668
  	int    gre_hlen;
d5a0a1e31   Al Viro   [IPV4]: encapsula...
669
  	__be32 dst;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
670
  	int    mtu;
e1a800022   Herbert Xu   gre: Add Transpar...
671
672
673
674
  	if (dev->type == ARPHRD_ETHER)
  		IPCB(skb)->flags = 0;
  
  	if (dev->header_ops && dev->type == ARPHRD_IPGRE) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
675
  		gre_hlen = 0;
b71d1d426   Eric Dumazet   inet: constify ip...
676
  		tiph = (const struct iphdr *)skb->data;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
677
678
679
680
681
682
683
  	} else {
  		gre_hlen = tunnel->hlen;
  		tiph = &tunnel->parms.iph;
  	}
  
  	if ((dst = tiph->daddr) == 0) {
  		/* NBMA tunnel */
adf30907d   Eric Dumazet   net: skb->dst acc...
684
  		if (skb_dst(skb) == NULL) {
e985aad72   Eric Dumazet   ip_gre: percpu st...
685
  			dev->stats.tx_fifo_errors++;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
686
687
688
689
  			goto tx_error;
  		}
  
  		if (skb->protocol == htons(ETH_P_IP)) {
511c3f92a   Eric Dumazet   net: skb->rtable ...
690
  			rt = skb_rtable(skb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
691
692
693
  			if ((dst = rt->rt_gateway) == 0)
  				goto tx_error_icmp;
  		}
dfd56b8b3   Eric Dumazet   net: use IS_ENABL...
694
  #if IS_ENABLED(CONFIG_IPV6)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
695
  		else if (skb->protocol == htons(ETH_P_IPV6)) {
272174550   David Miller   net: Rename dst_g...
696
  			struct neighbour *neigh = dst_get_neighbour_noref(skb_dst(skb));
b71d1d426   Eric Dumazet   inet: constify ip...
697
  			const struct in6_addr *addr6;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
698
  			int addr_type;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
699
700
701
  
  			if (neigh == NULL)
  				goto tx_error;
b71d1d426   Eric Dumazet   inet: constify ip...
702
  			addr6 = (const struct in6_addr *)&neigh->primary_key;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
703
704
705
  			addr_type = ipv6_addr_type(addr6);
  
  			if (addr_type == IPV6_ADDR_ANY) {
0660e03f6   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
706
  				addr6 = &ipv6_hdr(skb)->daddr;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
707
708
709
710
711
712
713
714
715
716
717
718
719
720
  				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;
ee686ca91   Andreas Jaggi   gre: fix ToS/Diff...
721
722
  	if (tos == 1) {
  		tos = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
723
724
  		if (skb->protocol == htons(ETH_P_IP))
  			tos = old_iph->tos;
dd4ba83dc   Stephen Hemminger   gre: propagate ip...
725
  		else if (skb->protocol == htons(ETH_P_IPV6))
b71d1d426   Eric Dumazet   inet: constify ip...
726
  			tos = ipv6_get_dsfield((const struct ipv6hdr *)old_iph);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
727
  	}
cbb1e85f9   David S. Miller   ipv4: Kill rt->rt...
728
  	rt = ip_route_output_gre(dev_net(dev), &fl4, dst, tiph->saddr,
78fbfd8a6   David S. Miller   ipv4: Create and ...
729
730
731
732
733
  				 tunnel->parms.o_key, RT_TOS(tos),
  				 tunnel->parms.link);
  	if (IS_ERR(rt)) {
  		dev->stats.tx_carrier_errors++;
  		goto tx_error;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
734
  	}
d8d1f30b9   Changli Gao   net-next: remove ...
735
  	tdev = rt->dst.dev;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
736
737
738
  
  	if (tdev == dev) {
  		ip_rt_put(rt);
e985aad72   Eric Dumazet   ip_gre: percpu st...
739
  		dev->stats.collisions++;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
740
741
742
743
744
  		goto tx_error;
  	}
  
  	df = tiph->frag_off;
  	if (df)
d8d1f30b9   Changli Gao   net-next: remove ...
745
  		mtu = dst_mtu(&rt->dst) - dev->hard_header_len - tunnel->hlen;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
746
  	else
adf30907d   Eric Dumazet   net: skb->dst acc...
747
  		mtu = skb_dst(skb) ? dst_mtu(skb_dst(skb)) : dev->mtu;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
748

adf30907d   Eric Dumazet   net: skb->dst acc...
749
750
  	if (skb_dst(skb))
  		skb_dst(skb)->ops->update_pmtu(skb_dst(skb), mtu);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
751
752
753
754
755
756
757
758
759
760
761
  
  	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;
  		}
  	}
dfd56b8b3   Eric Dumazet   net: use IS_ENABL...
762
  #if IS_ENABLED(CONFIG_IPV6)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
763
  	else if (skb->protocol == htons(ETH_P_IPV6)) {
adf30907d   Eric Dumazet   net: skb->dst acc...
764
  		struct rt6_info *rt6 = (struct rt6_info *)skb_dst(skb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
765

adf30907d   Eric Dumazet   net: skb->dst acc...
766
  		if (rt6 && mtu < dst_mtu(skb_dst(skb)) && mtu >= IPV6_MIN_MTU) {
f97c1e0c6   Joe Perches   [IPV4] net/ipv4: ...
767
768
  			if ((tunnel->parms.iph.daddr &&
  			     !ipv4_is_multicast(tunnel->parms.iph.daddr)) ||
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
769
770
  			    rt6->rt6i_dst.plen == 128) {
  				rt6->rt6i_flags |= RTF_MODIFIED;
defb3519a   David S. Miller   net: Abstract awa...
771
  				dst_metric_set(skb_dst(skb), RTAX_MTU, mtu);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
772
773
774
775
  			}
  		}
  
  		if (mtu >= IPV6_MIN_MTU && mtu < skb->len - tunnel->hlen + gre_hlen) {
3ffe533c8   Alexey Dobriyan   ipv6: drop unused...
776
  			icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
777
778
779
780
781
782
783
  			ip_rt_put(rt);
  			goto tx_error;
  		}
  	}
  #endif
  
  	if (tunnel->err_count > 0) {
da6185d87   Wei Yongjun   gre: used time_be...
784
785
  		if (time_before(jiffies,
  				tunnel->err_time + IPTUNNEL_ERR_TIMEO)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
786
787
788
789
790
791
  			tunnel->err_count--;
  
  			dst_link_failure(skb);
  		} else
  			tunnel->err_count = 0;
  	}
d8d1f30b9   Changli Gao   net-next: remove ...
792
  	max_headroom = LL_RESERVED_SPACE(tdev) + gre_hlen + rt->dst.header_len;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
793

cfbba49d8   Patrick McHardy   [NET]: Avoid copy...
794
795
  	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
796
  		struct sk_buff *new_skb = skb_realloc_headroom(skb, max_headroom);
805dc1d60   Herbert Xu   ip_gre: Set neede...
797
798
  		if (max_headroom > dev->needed_headroom)
  			dev->needed_headroom = max_headroom;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
799
800
  		if (!new_skb) {
  			ip_rt_put(rt);
e985aad72   Eric Dumazet   ip_gre: percpu st...
801
  			dev->stats.tx_dropped++;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
802
  			dev_kfree_skb(skb);
6ed106549   Patrick McHardy   net: use NETDEV_T...
803
  			return NETDEV_TX_OK;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
804
805
806
807
808
  		}
  		if (skb->sk)
  			skb_set_owner_w(new_skb, skb->sk);
  		dev_kfree_skb(skb);
  		skb = new_skb;
eddc9ec53   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
809
  		old_iph = ip_hdr(skb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
810
  	}
64194c31a   Herbert Xu   inet: Make tunnel...
811
  	skb_reset_transport_header(skb);
e2d1bca7e   Arnaldo Carvalho de Melo   [SK_BUFF]: Use sk...
812
813
  	skb_push(skb, gre_hlen);
  	skb_reset_network_header(skb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
814
  	memset(&(IPCB(skb)->opt), 0, sizeof(IPCB(skb)->opt));
48d5cad87   Patrick McHardy   [XFRM]: Fix SNAT-...
815
816
  	IPCB(skb)->flags &= ~(IPSKB_XFRM_TUNNEL_SIZE | IPSKB_XFRM_TRANSFORMED |
  			      IPSKB_REROUTED);
adf30907d   Eric Dumazet   net: skb->dst acc...
817
  	skb_dst_drop(skb);
d8d1f30b9   Changli Gao   net-next: remove ...
818
  	skb_dst_set(skb, &rt->dst);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
819
820
821
822
  
  	/*
  	 *	Push down and install the IPIP header.
  	 */
eddc9ec53   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
823
  	iph 			=	ip_hdr(skb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
824
825
826
827
828
  	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);
cbb1e85f9   David S. Miller   ipv4: Kill rt->rt...
829
830
  	iph->daddr		=	fl4.daddr;
  	iph->saddr		=	fl4.saddr;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
831
832
833
834
  
  	if ((iph->ttl = tiph->ttl) == 0) {
  		if (skb->protocol == htons(ETH_P_IP))
  			iph->ttl = old_iph->ttl;
dfd56b8b3   Eric Dumazet   net: use IS_ENABL...
835
  #if IS_ENABLED(CONFIG_IPV6)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
836
  		else if (skb->protocol == htons(ETH_P_IPV6))
b71d1d426   Eric Dumazet   inet: constify ip...
837
  			iph->ttl = ((const struct ipv6hdr *)old_iph)->hop_limit;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
838
839
  #endif
  		else
323e126f0   David S. Miller   ipv4: Don't pre-s...
840
  			iph->ttl = ip4_dst_hoplimit(&rt->dst);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
841
  	}
e1a800022   Herbert Xu   gre: Add Transpar...
842
843
844
  	((__be16 *)(iph + 1))[0] = tunnel->parms.o_flags;
  	((__be16 *)(iph + 1))[1] = (dev->type == ARPHRD_ETHER) ?
  				   htons(ETH_P_TEB) : skb->protocol;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
845
846
  
  	if (tunnel->parms.o_flags&(GRE_KEY|GRE_CSUM|GRE_SEQ)) {
d5a0a1e31   Al Viro   [IPV4]: encapsula...
847
  		__be32 *ptr = (__be32*)(((u8*)iph) + tunnel->hlen - 4);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
848
849
850
851
852
853
854
855
856
857
858
859
  
  		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;
5f92a7388   Al Viro   [NET]: Annotate c...
860
  			*(__sum16*)ptr = ip_compute_csum((void*)(iph+1), skb->len - sizeof(struct iphdr));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
861
862
863
864
  		}
  	}
  
  	nf_reset(skb);
e985aad72   Eric Dumazet   ip_gre: percpu st...
865
866
  	tstats = this_cpu_ptr(dev->tstats);
  	__IPTUNNEL_XMIT(tstats, &dev->stats);
6ed106549   Patrick McHardy   net: use NETDEV_T...
867
  	return NETDEV_TX_OK;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
868
869
870
871
872
  
  tx_error_icmp:
  	dst_link_failure(skb);
  
  tx_error:
e985aad72   Eric Dumazet   ip_gre: percpu st...
873
  	dev->stats.tx_errors++;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
874
  	dev_kfree_skb(skb);
6ed106549   Patrick McHardy   net: use NETDEV_T...
875
  	return NETDEV_TX_OK;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
876
  }
42aa91626   Herbert Xu   gre: Move MTU set...
877
  static int ipgre_tunnel_bind_dev(struct net_device *dev)
ee34c1eb3   Michal Schmidt   [IP_GRE]: Rebindi...
878
879
880
  {
  	struct net_device *tdev = NULL;
  	struct ip_tunnel *tunnel;
b71d1d426   Eric Dumazet   inet: constify ip...
881
  	const struct iphdr *iph;
ee34c1eb3   Michal Schmidt   [IP_GRE]: Rebindi...
882
883
884
885
886
887
  	int hlen = LL_MAX_HEADER;
  	int mtu = ETH_DATA_LEN;
  	int addend = sizeof(struct iphdr) + 4;
  
  	tunnel = netdev_priv(dev);
  	iph = &tunnel->parms.iph;
c95b819ad   Herbert Xu   gre: Use needed_h...
888
  	/* Guess output device to choose reasonable mtu and needed_headroom */
ee34c1eb3   Michal Schmidt   [IP_GRE]: Rebindi...
889
890
  
  	if (iph->daddr) {
cbb1e85f9   David S. Miller   ipv4: Kill rt->rt...
891
892
893
894
895
896
897
898
  		struct flowi4 fl4;
  		struct rtable *rt;
  
  		rt = ip_route_output_gre(dev_net(dev), &fl4,
  					 iph->daddr, iph->saddr,
  					 tunnel->parms.o_key,
  					 RT_TOS(iph->tos),
  					 tunnel->parms.link);
b23dd4fe4   David S. Miller   ipv4: Make output...
899
  		if (!IS_ERR(rt)) {
d8d1f30b9   Changli Gao   net-next: remove ...
900
  			tdev = rt->dst.dev;
ee34c1eb3   Michal Schmidt   [IP_GRE]: Rebindi...
901
902
  			ip_rt_put(rt);
  		}
e1a800022   Herbert Xu   gre: Add Transpar...
903
904
905
  
  		if (dev->type != ARPHRD_ETHER)
  			dev->flags |= IFF_POINTOPOINT;
ee34c1eb3   Michal Schmidt   [IP_GRE]: Rebindi...
906
907
908
  	}
  
  	if (!tdev && tunnel->parms.link)
96635522f   Pavel Emelyanov   [GRE]: Use proper...
909
  		tdev = __dev_get_by_index(dev_net(dev), tunnel->parms.link);
ee34c1eb3   Michal Schmidt   [IP_GRE]: Rebindi...
910
911
  
  	if (tdev) {
c95b819ad   Herbert Xu   gre: Use needed_h...
912
  		hlen = tdev->hard_header_len + tdev->needed_headroom;
ee34c1eb3   Michal Schmidt   [IP_GRE]: Rebindi...
913
914
915
916
917
918
919
920
921
922
923
924
925
  		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;
  	}
c95b819ad   Herbert Xu   gre: Use needed_h...
926
  	dev->needed_headroom = addend + hlen;
8cdb04563   Tom Goff   gre: Fix MTU calc...
927
  	mtu -= dev->hard_header_len + addend;
42aa91626   Herbert Xu   gre: Move MTU set...
928
929
930
  
  	if (mtu < 68)
  		mtu = 68;
ee34c1eb3   Michal Schmidt   [IP_GRE]: Rebindi...
931
  	tunnel->hlen = addend;
42aa91626   Herbert Xu   gre: Move MTU set...
932
  	return mtu;
ee34c1eb3   Michal Schmidt   [IP_GRE]: Rebindi...
933
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
934
935
936
937
938
939
  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;
f57e7d5a7   Pavel Emelyanov   [GRE]: Add net/gr...
940
941
  	struct net *net = dev_net(dev);
  	struct ipgre_net *ign = net_generic(net, ipgre_net_id);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
942
943
944
945
  
  	switch (cmd) {
  	case SIOCGETTUNNEL:
  		t = NULL;
7daa00048   Pavel Emelyanov   [GRE]: Make the f...
946
  		if (dev == ign->fb_tunnel_dev) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
947
948
949
950
  			if (copy_from_user(&p, ifr->ifr_ifru.ifru_data, sizeof(p))) {
  				err = -EFAULT;
  				break;
  			}
f57e7d5a7   Pavel Emelyanov   [GRE]: Add net/gr...
951
  			t = ipgre_tunnel_locate(net, &p, 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
952
953
  		}
  		if (t == NULL)
2941a4863   Patrick McHardy   [NET]: Convert ne...
954
  			t = netdev_priv(dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
  		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;
f57e7d5a7   Pavel Emelyanov   [GRE]: Add net/gr...
982
  		t = ipgre_tunnel_locate(net, &p, cmd == SIOCADDTUNNEL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
983

7daa00048   Pavel Emelyanov   [GRE]: Make the f...
984
  		if (dev != ign->fb_tunnel_dev && cmd == SIOCCHGTUNNEL) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
985
986
987
988
989
990
  			if (t != NULL) {
  				if (t->dev != dev) {
  					err = -EEXIST;
  					break;
  				}
  			} else {
1507850b4   Eric Dumazet   gre: get rid of i...
991
  				unsigned int nflags = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
992

2941a4863   Patrick McHardy   [NET]: Convert ne...
993
  				t = netdev_priv(dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
994

f97c1e0c6   Joe Perches   [IPV4] net/ipv4: ...
995
  				if (ipv4_is_multicast(p.iph.daddr))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
996
997
998
999
1000
1001
1002
1003
  					nflags = IFF_BROADCAST;
  				else if (p.iph.daddr)
  					nflags = IFF_POINTOPOINT;
  
  				if ((dev->flags^nflags)&(IFF_POINTOPOINT|IFF_BROADCAST)) {
  					err = -EINVAL;
  					break;
  				}
f57e7d5a7   Pavel Emelyanov   [GRE]: Add net/gr...
1004
  				ipgre_tunnel_unlink(ign, t);
74b0b85b8   Pavel Emelyanov   tunnels: Fix tunn...
1005
  				synchronize_net();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1006
1007
1008
1009
1010
1011
  				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);
f57e7d5a7   Pavel Emelyanov   [GRE]: Add net/gr...
1012
  				ipgre_tunnel_link(ign, t);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
  				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;
ee34c1eb3   Michal Schmidt   [IP_GRE]: Rebindi...
1023
1024
  				if (t->parms.link != p.link) {
  					t->parms.link = p.link;
42aa91626   Herbert Xu   gre: Move MTU set...
1025
  					dev->mtu = ipgre_tunnel_bind_dev(dev);
ee34c1eb3   Michal Schmidt   [IP_GRE]: Rebindi...
1026
1027
  					netdev_state_change(dev);
  				}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
  			}
  			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;
7daa00048   Pavel Emelyanov   [GRE]: Make the f...
1039
  		if (dev == ign->fb_tunnel_dev) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1040
1041
1042
1043
  			err = -EFAULT;
  			if (copy_from_user(&p, ifr->ifr_ifru.ifru_data, sizeof(p)))
  				goto done;
  			err = -ENOENT;
f57e7d5a7   Pavel Emelyanov   [GRE]: Add net/gr...
1044
  			if ((t = ipgre_tunnel_locate(net, &p, 0)) == NULL)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1045
1046
  				goto done;
  			err = -EPERM;
7daa00048   Pavel Emelyanov   [GRE]: Make the f...
1047
  			if (t == netdev_priv(ign->fb_tunnel_dev))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1048
1049
1050
  				goto done;
  			dev = t->dev;
  		}
22f8cde5b   Stephen Hemminger   [NET]: unregister...
1051
1052
  		unregister_netdevice(dev);
  		err = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1053
1054
1055
1056
1057
1058
1059
1060
1061
  		break;
  
  	default:
  		err = -EINVAL;
  	}
  
  done:
  	return err;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1062
1063
  static int ipgre_tunnel_change_mtu(struct net_device *dev, int new_mtu)
  {
2941a4863   Patrick McHardy   [NET]: Convert ne...
1064
  	struct ip_tunnel *tunnel = netdev_priv(dev);
c95b819ad   Herbert Xu   gre: Use needed_h...
1065
1066
  	if (new_mtu < 68 ||
  	    new_mtu > 0xFFF8 - dev->hard_header_len - tunnel->hlen)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1067
1068
1069
1070
  		return -EINVAL;
  	dev->mtu = new_mtu;
  	return 0;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1071
1072
1073
1074
1075
1076
1077
1078
1079
  /* 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).
e905a9eda   YOSHIFUJI Hideaki   [NET] IPV4: Fix w...
1080

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
     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
     ...
  
   */
3b04ddde0   Stephen Hemminger   [NET]: Move hardw...
1099
1100
  static int ipgre_header(struct sk_buff *skb, struct net_device *dev,
  			unsigned short type,
1507850b4   Eric Dumazet   gre: get rid of i...
1101
  			const void *daddr, const void *saddr, unsigned int len)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1102
  {
2941a4863   Patrick McHardy   [NET]: Convert ne...
1103
  	struct ip_tunnel *t = netdev_priv(dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1104
  	struct iphdr *iph = (struct iphdr *)skb_push(skb, t->hlen);
d5a0a1e31   Al Viro   [IPV4]: encapsula...
1105
  	__be16 *p = (__be16*)(iph+1);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1106
1107
1108
1109
1110
1111
  
  	memcpy(iph, &t->parms.iph, sizeof(struct iphdr));
  	p[0]		= t->parms.o_flags;
  	p[1]		= htons(type);
  
  	/*
e905a9eda   YOSHIFUJI Hideaki   [NET] IPV4: Fix w...
1112
  	 *	Set the source hardware address.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1113
  	 */
e905a9eda   YOSHIFUJI Hideaki   [NET] IPV4: Fix w...
1114

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1115
1116
  	if (saddr)
  		memcpy(&iph->saddr, saddr, 4);
6d55cb91a   Timo Teräs   gre: fix hard hea...
1117
  	if (daddr)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1118
  		memcpy(&iph->daddr, daddr, 4);
6d55cb91a   Timo Teräs   gre: fix hard hea...
1119
  	if (iph->daddr)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1120
  		return t->hlen;
e905a9eda   YOSHIFUJI Hideaki   [NET] IPV4: Fix w...
1121

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1122
1123
  	return -t->hlen;
  }
6a5f44d7a   Timo Teras   [IPV4] ip_gre: se...
1124
1125
  static int ipgre_header_parse(const struct sk_buff *skb, unsigned char *haddr)
  {
b71d1d426   Eric Dumazet   inet: constify ip...
1126
  	const struct iphdr *iph = (const struct iphdr *) skb_mac_header(skb);
6a5f44d7a   Timo Teras   [IPV4] ip_gre: se...
1127
1128
1129
  	memcpy(haddr, &iph->saddr, 4);
  	return 4;
  }
3b04ddde0   Stephen Hemminger   [NET]: Move hardw...
1130
1131
  static const struct header_ops ipgre_header_ops = {
  	.create	= ipgre_header,
6a5f44d7a   Timo Teras   [IPV4] ip_gre: se...
1132
  	.parse	= ipgre_header_parse,
3b04ddde0   Stephen Hemminger   [NET]: Move hardw...
1133
  };
6a5f44d7a   Timo Teras   [IPV4] ip_gre: se...
1134
  #ifdef CONFIG_NET_IPGRE_BROADCAST
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1135
1136
  static int ipgre_open(struct net_device *dev)
  {
2941a4863   Patrick McHardy   [NET]: Convert ne...
1137
  	struct ip_tunnel *t = netdev_priv(dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1138

f97c1e0c6   Joe Perches   [IPV4] net/ipv4: ...
1139
  	if (ipv4_is_multicast(t->parms.iph.daddr)) {
cbb1e85f9   David S. Miller   ipv4: Kill rt->rt...
1140
1141
1142
1143
1144
1145
1146
1147
1148
  		struct flowi4 fl4;
  		struct rtable *rt;
  
  		rt = ip_route_output_gre(dev_net(dev), &fl4,
  					 t->parms.iph.daddr,
  					 t->parms.iph.saddr,
  					 t->parms.o_key,
  					 RT_TOS(t->parms.iph.tos),
  					 t->parms.link);
b23dd4fe4   David S. Miller   ipv4: Make output...
1149
  		if (IS_ERR(rt))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1150
  			return -EADDRNOTAVAIL;
d8d1f30b9   Changli Gao   net-next: remove ...
1151
  		dev = rt->dst.dev;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1152
  		ip_rt_put(rt);
e5ed63991   Herbert Xu   [IPV4]: Replace _...
1153
  		if (__in_dev_get_rtnl(dev) == NULL)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1154
1155
  			return -EADDRNOTAVAIL;
  		t->mlink = dev->ifindex;
e5ed63991   Herbert Xu   [IPV4]: Replace _...
1156
  		ip_mc_inc_group(__in_dev_get_rtnl(dev), t->parms.iph.daddr);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1157
1158
1159
1160
1161
1162
  	}
  	return 0;
  }
  
  static int ipgre_close(struct net_device *dev)
  {
2941a4863   Patrick McHardy   [NET]: Convert ne...
1163
  	struct ip_tunnel *t = netdev_priv(dev);
b8c26a33c   Stephen Hemminger   ipgre: convert to...
1164

f97c1e0c6   Joe Perches   [IPV4] net/ipv4: ...
1165
  	if (ipv4_is_multicast(t->parms.iph.daddr) && t->mlink) {
7fee0ca23   Denis V. Lunev   [NETNS]: Add netn...
1166
  		struct in_device *in_dev;
c346dca10   YOSHIFUJI Hideaki   [NET] NETNS: Omit...
1167
  		in_dev = inetdev_by_index(dev_net(dev), t->mlink);
8723e1b4a   Eric Dumazet   inet: RCU changes...
1168
  		if (in_dev)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1169
  			ip_mc_dec_group(in_dev, t->parms.iph.daddr);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1170
1171
1172
1173
1174
  	}
  	return 0;
  }
  
  #endif
b8c26a33c   Stephen Hemminger   ipgre: convert to...
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
  static const struct net_device_ops ipgre_netdev_ops = {
  	.ndo_init		= ipgre_tunnel_init,
  	.ndo_uninit		= ipgre_tunnel_uninit,
  #ifdef CONFIG_NET_IPGRE_BROADCAST
  	.ndo_open		= ipgre_open,
  	.ndo_stop		= ipgre_close,
  #endif
  	.ndo_start_xmit		= ipgre_tunnel_xmit,
  	.ndo_do_ioctl		= ipgre_tunnel_ioctl,
  	.ndo_change_mtu		= ipgre_tunnel_change_mtu,
e985aad72   Eric Dumazet   ip_gre: percpu st...
1185
  	.ndo_get_stats		= ipgre_get_stats,
b8c26a33c   Stephen Hemminger   ipgre: convert to...
1186
  };
e985aad72   Eric Dumazet   ip_gre: percpu st...
1187
1188
1189
1190
1191
  static void ipgre_dev_free(struct net_device *dev)
  {
  	free_percpu(dev->tstats);
  	free_netdev(dev);
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1192
1193
  static void ipgre_tunnel_setup(struct net_device *dev)
  {
b8c26a33c   Stephen Hemminger   ipgre: convert to...
1194
  	dev->netdev_ops		= &ipgre_netdev_ops;
e985aad72   Eric Dumazet   ip_gre: percpu st...
1195
  	dev->destructor 	= ipgre_dev_free;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1196
1197
  
  	dev->type		= ARPHRD_IPGRE;
c95b819ad   Herbert Xu   gre: Use needed_h...
1198
  	dev->needed_headroom 	= LL_MAX_HEADER + sizeof(struct iphdr) + 4;
46f25dffb   Kris Katterjohn   [NET]: Change 150...
1199
  	dev->mtu		= ETH_DATA_LEN - sizeof(struct iphdr) - 4;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1200
1201
1202
  	dev->flags		= IFF_NOARP;
  	dev->iflink		= 0;
  	dev->addr_len		= 4;
0b67eceb1   Pavel Emelyanov   [GRE]: Allow to c...
1203
  	dev->features		|= NETIF_F_NETNS_LOCAL;
108bfa895   Eric Dumazet   net: unset IFF_XM...
1204
  	dev->priv_flags		&= ~IFF_XMIT_DST_RELEASE;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1205
1206
1207
1208
  }
  
  static int ipgre_tunnel_init(struct net_device *dev)
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1209
1210
  	struct ip_tunnel *tunnel;
  	struct iphdr *iph;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1211

2941a4863   Patrick McHardy   [NET]: Convert ne...
1212
  	tunnel = netdev_priv(dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1213
1214
1215
1216
1217
1218
1219
  	iph = &tunnel->parms.iph;
  
  	tunnel->dev = dev;
  	strcpy(tunnel->parms.name, dev->name);
  
  	memcpy(dev->dev_addr, &tunnel->parms.iph.saddr, 4);
  	memcpy(dev->broadcast, &tunnel->parms.iph.daddr, 4);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1220
  	if (iph->daddr) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1221
  #ifdef CONFIG_NET_IPGRE_BROADCAST
f97c1e0c6   Joe Perches   [IPV4] net/ipv4: ...
1222
  		if (ipv4_is_multicast(iph->daddr)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1223
1224
1225
  			if (!iph->saddr)
  				return -EINVAL;
  			dev->flags = IFF_BROADCAST;
3b04ddde0   Stephen Hemminger   [NET]: Move hardw...
1226
  			dev->header_ops = &ipgre_header_ops;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1227
1228
  		}
  #endif
ee34c1eb3   Michal Schmidt   [IP_GRE]: Rebindi...
1229
  	} else
6a5f44d7a   Timo Teras   [IPV4] ip_gre: se...
1230
  		dev->header_ops = &ipgre_header_ops;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1231

e985aad72   Eric Dumazet   ip_gre: percpu st...
1232
1233
1234
  	dev->tstats = alloc_percpu(struct pcpu_tstats);
  	if (!dev->tstats)
  		return -ENOMEM;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1235
1236
  	return 0;
  }
b8c26a33c   Stephen Hemminger   ipgre: convert to...
1237
  static void ipgre_fb_tunnel_init(struct net_device *dev)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1238
  {
2941a4863   Patrick McHardy   [NET]: Convert ne...
1239
  	struct ip_tunnel *tunnel = netdev_priv(dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
  	struct iphdr *iph = &tunnel->parms.iph;
  
  	tunnel->dev = dev;
  	strcpy(tunnel->parms.name, dev->name);
  
  	iph->version		= 4;
  	iph->protocol		= IPPROTO_GRE;
  	iph->ihl		= 5;
  	tunnel->hlen		= sizeof(struct iphdr) + 4;
  
  	dev_hold(dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1251
  }
00959ade3   Dmitry Kozlov   PPTP: PPP over IP...
1252
1253
1254
  static const struct gre_protocol ipgre_protocol = {
  	.handler     = ipgre_rcv,
  	.err_handler = ipgre_err,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1255
  };
eef6dd65e   Eric Dumazet   gre: Optimize mul...
1256
  static void ipgre_destroy_tunnels(struct ipgre_net *ign, struct list_head *head)
eb8ce741a   Pavel Emelyanov   [GRE]: Make tunne...
1257
1258
1259
1260
1261
1262
  {
  	int prio;
  
  	for (prio = 0; prio < 4; prio++) {
  		int h;
  		for (h = 0; h < HASH_SIZE; h++) {
1507850b4   Eric Dumazet   gre: get rid of i...
1263
1264
1265
  			struct ip_tunnel *t;
  
  			t = rtnl_dereference(ign->tunnels[prio][h]);
eef6dd65e   Eric Dumazet   gre: Optimize mul...
1266
1267
1268
  
  			while (t != NULL) {
  				unregister_netdevice_queue(t->dev, head);
1507850b4   Eric Dumazet   gre: get rid of i...
1269
  				t = rtnl_dereference(t->next);
eef6dd65e   Eric Dumazet   gre: Optimize mul...
1270
  			}
eb8ce741a   Pavel Emelyanov   [GRE]: Make tunne...
1271
1272
1273
  		}
  	}
  }
2c8c1e729   Alexey Dobriyan   net: spread __net...
1274
  static int __net_init ipgre_init_net(struct net *net)
59a4c7594   Pavel Emelyanov   [GRE]: Introduce ...
1275
  {
cfb8fbf22   Eric W. Biederman   net: Simplify ip_...
1276
  	struct ipgre_net *ign = net_generic(net, ipgre_net_id);
59a4c7594   Pavel Emelyanov   [GRE]: Introduce ...
1277
  	int err;
59a4c7594   Pavel Emelyanov   [GRE]: Introduce ...
1278

7daa00048   Pavel Emelyanov   [GRE]: Make the f...
1279
1280
1281
1282
1283
1284
  	ign->fb_tunnel_dev = alloc_netdev(sizeof(struct ip_tunnel), "gre0",
  					   ipgre_tunnel_setup);
  	if (!ign->fb_tunnel_dev) {
  		err = -ENOMEM;
  		goto err_alloc_dev;
  	}
be77e5930   Alexey Dobriyan   net: fix tunnels ...
1285
  	dev_net_set(ign->fb_tunnel_dev, net);
7daa00048   Pavel Emelyanov   [GRE]: Make the f...
1286

b8c26a33c   Stephen Hemminger   ipgre: convert to...
1287
  	ipgre_fb_tunnel_init(ign->fb_tunnel_dev);
c19e654dd   Herbert Xu   gre: Add netlink ...
1288
  	ign->fb_tunnel_dev->rtnl_link_ops = &ipgre_link_ops;
7daa00048   Pavel Emelyanov   [GRE]: Make the f...
1289
1290
1291
  
  	if ((err = register_netdev(ign->fb_tunnel_dev)))
  		goto err_reg_dev;
3285ee3bb   Eric Dumazet   ip_gre: fix fallb...
1292
1293
  	rcu_assign_pointer(ign->tunnels_wc[0],
  			   netdev_priv(ign->fb_tunnel_dev));
59a4c7594   Pavel Emelyanov   [GRE]: Introduce ...
1294
  	return 0;
7daa00048   Pavel Emelyanov   [GRE]: Make the f...
1295
  err_reg_dev:
3285ee3bb   Eric Dumazet   ip_gre: fix fallb...
1296
  	ipgre_dev_free(ign->fb_tunnel_dev);
7daa00048   Pavel Emelyanov   [GRE]: Make the f...
1297
  err_alloc_dev:
59a4c7594   Pavel Emelyanov   [GRE]: Introduce ...
1298
1299
  	return err;
  }
2c8c1e729   Alexey Dobriyan   net: spread __net...
1300
  static void __net_exit ipgre_exit_net(struct net *net)
59a4c7594   Pavel Emelyanov   [GRE]: Introduce ...
1301
1302
  {
  	struct ipgre_net *ign;
eef6dd65e   Eric Dumazet   gre: Optimize mul...
1303
  	LIST_HEAD(list);
59a4c7594   Pavel Emelyanov   [GRE]: Introduce ...
1304
1305
  
  	ign = net_generic(net, ipgre_net_id);
7daa00048   Pavel Emelyanov   [GRE]: Make the f...
1306
  	rtnl_lock();
eef6dd65e   Eric Dumazet   gre: Optimize mul...
1307
1308
  	ipgre_destroy_tunnels(ign, &list);
  	unregister_netdevice_many(&list);
7daa00048   Pavel Emelyanov   [GRE]: Make the f...
1309
  	rtnl_unlock();
59a4c7594   Pavel Emelyanov   [GRE]: Introduce ...
1310
1311
1312
1313
1314
  }
  
  static struct pernet_operations ipgre_net_ops = {
  	.init = ipgre_init_net,
  	.exit = ipgre_exit_net,
cfb8fbf22   Eric W. Biederman   net: Simplify ip_...
1315
1316
  	.id   = &ipgre_net_id,
  	.size = sizeof(struct ipgre_net),
59a4c7594   Pavel Emelyanov   [GRE]: Introduce ...
1317
  };
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1318

c19e654dd   Herbert Xu   gre: Add netlink ...
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
  static int ipgre_tunnel_validate(struct nlattr *tb[], struct nlattr *data[])
  {
  	__be16 flags;
  
  	if (!data)
  		return 0;
  
  	flags = 0;
  	if (data[IFLA_GRE_IFLAGS])
  		flags |= nla_get_be16(data[IFLA_GRE_IFLAGS]);
  	if (data[IFLA_GRE_OFLAGS])
  		flags |= nla_get_be16(data[IFLA_GRE_OFLAGS]);
  	if (flags & (GRE_VERSION|GRE_ROUTING))
  		return -EINVAL;
  
  	return 0;
  }
e1a800022   Herbert Xu   gre: Add Transpar...
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
  static int ipgre_tap_validate(struct nlattr *tb[], struct nlattr *data[])
  {
  	__be32 daddr;
  
  	if (tb[IFLA_ADDRESS]) {
  		if (nla_len(tb[IFLA_ADDRESS]) != ETH_ALEN)
  			return -EINVAL;
  		if (!is_valid_ether_addr(nla_data(tb[IFLA_ADDRESS])))
  			return -EADDRNOTAVAIL;
  	}
  
  	if (!data)
  		goto out;
  
  	if (data[IFLA_GRE_REMOTE]) {
  		memcpy(&daddr, nla_data(data[IFLA_GRE_REMOTE]), 4);
  		if (!daddr)
  			return -EINVAL;
  	}
  
  out:
  	return ipgre_tunnel_validate(tb, data);
  }
c19e654dd   Herbert Xu   gre: Add netlink ...
1359
1360
1361
  static void ipgre_netlink_parms(struct nlattr *data[],
  				struct ip_tunnel_parm *parms)
  {
7bb82d924   Herbert Xu   gre: Initialise r...
1362
  	memset(parms, 0, sizeof(*parms));
c19e654dd   Herbert Xu   gre: Add netlink ...
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
  
  	parms->iph.protocol = IPPROTO_GRE;
  
  	if (!data)
  		return;
  
  	if (data[IFLA_GRE_LINK])
  		parms->link = nla_get_u32(data[IFLA_GRE_LINK]);
  
  	if (data[IFLA_GRE_IFLAGS])
  		parms->i_flags = nla_get_be16(data[IFLA_GRE_IFLAGS]);
  
  	if (data[IFLA_GRE_OFLAGS])
  		parms->o_flags = nla_get_be16(data[IFLA_GRE_OFLAGS]);
  
  	if (data[IFLA_GRE_IKEY])
  		parms->i_key = nla_get_be32(data[IFLA_GRE_IKEY]);
  
  	if (data[IFLA_GRE_OKEY])
  		parms->o_key = nla_get_be32(data[IFLA_GRE_OKEY]);
  
  	if (data[IFLA_GRE_LOCAL])
4d74f8ba1   Patrick McHardy   gre: minor cleanu...
1385
  		parms->iph.saddr = nla_get_be32(data[IFLA_GRE_LOCAL]);
c19e654dd   Herbert Xu   gre: Add netlink ...
1386
1387
  
  	if (data[IFLA_GRE_REMOTE])
4d74f8ba1   Patrick McHardy   gre: minor cleanu...
1388
  		parms->iph.daddr = nla_get_be32(data[IFLA_GRE_REMOTE]);
c19e654dd   Herbert Xu   gre: Add netlink ...
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
  
  	if (data[IFLA_GRE_TTL])
  		parms->iph.ttl = nla_get_u8(data[IFLA_GRE_TTL]);
  
  	if (data[IFLA_GRE_TOS])
  		parms->iph.tos = nla_get_u8(data[IFLA_GRE_TOS]);
  
  	if (!data[IFLA_GRE_PMTUDISC] || nla_get_u8(data[IFLA_GRE_PMTUDISC]))
  		parms->iph.frag_off = htons(IP_DF);
  }
e1a800022   Herbert Xu   gre: Add Transpar...
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
  static int ipgre_tap_init(struct net_device *dev)
  {
  	struct ip_tunnel *tunnel;
  
  	tunnel = netdev_priv(dev);
  
  	tunnel->dev = dev;
  	strcpy(tunnel->parms.name, dev->name);
  
  	ipgre_tunnel_bind_dev(dev);
e985aad72   Eric Dumazet   ip_gre: percpu st...
1409
1410
1411
  	dev->tstats = alloc_percpu(struct pcpu_tstats);
  	if (!dev->tstats)
  		return -ENOMEM;
e1a800022   Herbert Xu   gre: Add Transpar...
1412
1413
  	return 0;
  }
b8c26a33c   Stephen Hemminger   ipgre: convert to...
1414
1415
1416
1417
1418
1419
1420
  static const struct net_device_ops ipgre_tap_netdev_ops = {
  	.ndo_init		= ipgre_tap_init,
  	.ndo_uninit		= ipgre_tunnel_uninit,
  	.ndo_start_xmit		= ipgre_tunnel_xmit,
  	.ndo_set_mac_address 	= eth_mac_addr,
  	.ndo_validate_addr	= eth_validate_addr,
  	.ndo_change_mtu		= ipgre_tunnel_change_mtu,
e985aad72   Eric Dumazet   ip_gre: percpu st...
1421
  	.ndo_get_stats		= ipgre_get_stats,
b8c26a33c   Stephen Hemminger   ipgre: convert to...
1422
  };
e1a800022   Herbert Xu   gre: Add Transpar...
1423
1424
1425
1426
  static void ipgre_tap_setup(struct net_device *dev)
  {
  
  	ether_setup(dev);
2e9526b35   Herbert Xu   gre: Fix dev_addr...
1427
  	dev->netdev_ops		= &ipgre_tap_netdev_ops;
e985aad72   Eric Dumazet   ip_gre: percpu st...
1428
  	dev->destructor 	= ipgre_dev_free;
e1a800022   Herbert Xu   gre: Add Transpar...
1429
1430
1431
1432
  
  	dev->iflink		= 0;
  	dev->features		|= NETIF_F_NETNS_LOCAL;
  }
81adee47d   Eric W. Biederman   net: Support spec...
1433
  static int ipgre_newlink(struct net *src_net, struct net_device *dev, struct nlattr *tb[],
c19e654dd   Herbert Xu   gre: Add netlink ...
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
  			 struct nlattr *data[])
  {
  	struct ip_tunnel *nt;
  	struct net *net = dev_net(dev);
  	struct ipgre_net *ign = net_generic(net, ipgre_net_id);
  	int mtu;
  	int err;
  
  	nt = netdev_priv(dev);
  	ipgre_netlink_parms(data, &nt->parms);
e1a800022   Herbert Xu   gre: Add Transpar...
1444
  	if (ipgre_tunnel_find(net, &nt->parms, dev->type))
c19e654dd   Herbert Xu   gre: Add netlink ...
1445
  		return -EEXIST;
e1a800022   Herbert Xu   gre: Add Transpar...
1446
1447
  	if (dev->type == ARPHRD_ETHER && !tb[IFLA_ADDRESS])
  		random_ether_addr(dev->dev_addr);
c19e654dd   Herbert Xu   gre: Add netlink ...
1448
1449
1450
  	mtu = ipgre_tunnel_bind_dev(dev);
  	if (!tb[IFLA_MTU])
  		dev->mtu = mtu;
b790e01ae   Eric Dumazet   ip_gre: lockless ...
1451
1452
1453
  	/* Can use a lockless transmit, unless we generate output sequences */
  	if (!(nt->parms.o_flags & GRE_SEQ))
  		dev->features |= NETIF_F_LLTX;
c19e654dd   Herbert Xu   gre: Add netlink ...
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
  	err = register_netdevice(dev);
  	if (err)
  		goto out;
  
  	dev_hold(dev);
  	ipgre_tunnel_link(ign, nt);
  
  out:
  	return err;
  }
  
  static int ipgre_changelink(struct net_device *dev, struct nlattr *tb[],
  			    struct nlattr *data[])
  {
  	struct ip_tunnel *t, *nt;
  	struct net *net = dev_net(dev);
  	struct ipgre_net *ign = net_generic(net, ipgre_net_id);
  	struct ip_tunnel_parm p;
  	int mtu;
  
  	if (dev == ign->fb_tunnel_dev)
  		return -EINVAL;
  
  	nt = netdev_priv(dev);
  	ipgre_netlink_parms(data, &p);
  
  	t = ipgre_tunnel_locate(net, &p, 0);
  
  	if (t) {
  		if (t->dev != dev)
  			return -EEXIST;
  	} else {
c19e654dd   Herbert Xu   gre: Add netlink ...
1486
  		t = nt;
2e9526b35   Herbert Xu   gre: Fix dev_addr...
1487
  		if (dev->type != ARPHRD_ETHER) {
1507850b4   Eric Dumazet   gre: get rid of i...
1488
  			unsigned int nflags = 0;
c19e654dd   Herbert Xu   gre: Add netlink ...
1489

2e9526b35   Herbert Xu   gre: Fix dev_addr...
1490
1491
1492
1493
1494
1495
1496
1497
1498
  			if (ipv4_is_multicast(p.iph.daddr))
  				nflags = IFF_BROADCAST;
  			else if (p.iph.daddr)
  				nflags = IFF_POINTOPOINT;
  
  			if ((dev->flags ^ nflags) &
  			    (IFF_POINTOPOINT | IFF_BROADCAST))
  				return -EINVAL;
  		}
c19e654dd   Herbert Xu   gre: Add netlink ...
1499
1500
1501
1502
1503
  
  		ipgre_tunnel_unlink(ign, t);
  		t->parms.iph.saddr = p.iph.saddr;
  		t->parms.iph.daddr = p.iph.daddr;
  		t->parms.i_key = p.i_key;
2e9526b35   Herbert Xu   gre: Fix dev_addr...
1504
1505
1506
1507
  		if (dev->type != ARPHRD_ETHER) {
  			memcpy(dev->dev_addr, &p.iph.saddr, 4);
  			memcpy(dev->broadcast, &p.iph.daddr, 4);
  		}
c19e654dd   Herbert Xu   gre: Add netlink ...
1508
1509
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
1556
1557
1558
1559
1560
1561
  		ipgre_tunnel_link(ign, t);
  		netdev_state_change(dev);
  	}
  
  	t->parms.o_key = p.o_key;
  	t->parms.iph.ttl = p.iph.ttl;
  	t->parms.iph.tos = p.iph.tos;
  	t->parms.iph.frag_off = p.iph.frag_off;
  
  	if (t->parms.link != p.link) {
  		t->parms.link = p.link;
  		mtu = ipgre_tunnel_bind_dev(dev);
  		if (!tb[IFLA_MTU])
  			dev->mtu = mtu;
  		netdev_state_change(dev);
  	}
  
  	return 0;
  }
  
  static size_t ipgre_get_size(const struct net_device *dev)
  {
  	return
  		/* IFLA_GRE_LINK */
  		nla_total_size(4) +
  		/* IFLA_GRE_IFLAGS */
  		nla_total_size(2) +
  		/* IFLA_GRE_OFLAGS */
  		nla_total_size(2) +
  		/* IFLA_GRE_IKEY */
  		nla_total_size(4) +
  		/* IFLA_GRE_OKEY */
  		nla_total_size(4) +
  		/* IFLA_GRE_LOCAL */
  		nla_total_size(4) +
  		/* IFLA_GRE_REMOTE */
  		nla_total_size(4) +
  		/* IFLA_GRE_TTL */
  		nla_total_size(1) +
  		/* IFLA_GRE_TOS */
  		nla_total_size(1) +
  		/* IFLA_GRE_PMTUDISC */
  		nla_total_size(1) +
  		0;
  }
  
  static int ipgre_fill_info(struct sk_buff *skb, const struct net_device *dev)
  {
  	struct ip_tunnel *t = netdev_priv(dev);
  	struct ip_tunnel_parm *p = &t->parms;
  
  	NLA_PUT_U32(skb, IFLA_GRE_LINK, p->link);
  	NLA_PUT_BE16(skb, IFLA_GRE_IFLAGS, p->i_flags);
  	NLA_PUT_BE16(skb, IFLA_GRE_OFLAGS, p->o_flags);
ba9e64b1c   Patrick McHardy   gre: fix copy and...
1562
1563
  	NLA_PUT_BE32(skb, IFLA_GRE_IKEY, p->i_key);
  	NLA_PUT_BE32(skb, IFLA_GRE_OKEY, p->o_key);
4d74f8ba1   Patrick McHardy   gre: minor cleanu...
1564
1565
  	NLA_PUT_BE32(skb, IFLA_GRE_LOCAL, p->iph.saddr);
  	NLA_PUT_BE32(skb, IFLA_GRE_REMOTE, p->iph.daddr);
c19e654dd   Herbert Xu   gre: Add netlink ...
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
  	NLA_PUT_U8(skb, IFLA_GRE_TTL, p->iph.ttl);
  	NLA_PUT_U8(skb, IFLA_GRE_TOS, p->iph.tos);
  	NLA_PUT_U8(skb, IFLA_GRE_PMTUDISC, !!(p->iph.frag_off & htons(IP_DF)));
  
  	return 0;
  
  nla_put_failure:
  	return -EMSGSIZE;
  }
  
  static const struct nla_policy ipgre_policy[IFLA_GRE_MAX + 1] = {
  	[IFLA_GRE_LINK]		= { .type = NLA_U32 },
  	[IFLA_GRE_IFLAGS]	= { .type = NLA_U16 },
  	[IFLA_GRE_OFLAGS]	= { .type = NLA_U16 },
  	[IFLA_GRE_IKEY]		= { .type = NLA_U32 },
  	[IFLA_GRE_OKEY]		= { .type = NLA_U32 },
4d74f8ba1   Patrick McHardy   gre: minor cleanu...
1582
1583
  	[IFLA_GRE_LOCAL]	= { .len = FIELD_SIZEOF(struct iphdr, saddr) },
  	[IFLA_GRE_REMOTE]	= { .len = FIELD_SIZEOF(struct iphdr, daddr) },
c19e654dd   Herbert Xu   gre: Add netlink ...
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
  	[IFLA_GRE_TTL]		= { .type = NLA_U8 },
  	[IFLA_GRE_TOS]		= { .type = NLA_U8 },
  	[IFLA_GRE_PMTUDISC]	= { .type = NLA_U8 },
  };
  
  static struct rtnl_link_ops ipgre_link_ops __read_mostly = {
  	.kind		= "gre",
  	.maxtype	= IFLA_GRE_MAX,
  	.policy		= ipgre_policy,
  	.priv_size	= sizeof(struct ip_tunnel),
  	.setup		= ipgre_tunnel_setup,
  	.validate	= ipgre_tunnel_validate,
  	.newlink	= ipgre_newlink,
  	.changelink	= ipgre_changelink,
  	.get_size	= ipgre_get_size,
  	.fill_info	= ipgre_fill_info,
  };
e1a800022   Herbert Xu   gre: Add Transpar...
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
  static struct rtnl_link_ops ipgre_tap_ops __read_mostly = {
  	.kind		= "gretap",
  	.maxtype	= IFLA_GRE_MAX,
  	.policy		= ipgre_policy,
  	.priv_size	= sizeof(struct ip_tunnel),
  	.setup		= ipgre_tap_setup,
  	.validate	= ipgre_tap_validate,
  	.newlink	= ipgre_newlink,
  	.changelink	= ipgre_changelink,
  	.get_size	= ipgre_get_size,
  	.fill_info	= ipgre_fill_info,
  };
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
  /*
   *	And now the modules code and kernel interface.
   */
  
  static int __init ipgre_init(void)
  {
  	int err;
  
  	printk(KERN_INFO "GRE over IPv4 tunneling driver
  ");
cfb8fbf22   Eric W. Biederman   net: Simplify ip_...
1623
  	err = register_pernet_device(&ipgre_net_ops);
59a4c7594   Pavel Emelyanov   [GRE]: Introduce ...
1624
  	if (err < 0)
c2892f027   Alexey Dobriyan   gre: fix netns vs...
1625
  		return err;
00959ade3   Dmitry Kozlov   PPTP: PPP over IP...
1626
  	err = gre_add_protocol(&ipgre_protocol, GREPROTO_CISCO);
c2892f027   Alexey Dobriyan   gre: fix netns vs...
1627
1628
1629
1630
1631
  	if (err < 0) {
  		printk(KERN_INFO "ipgre init: can't add protocol
  ");
  		goto add_proto_failed;
  	}
7daa00048   Pavel Emelyanov   [GRE]: Make the f...
1632

c19e654dd   Herbert Xu   gre: Add netlink ...
1633
1634
1635
  	err = rtnl_link_register(&ipgre_link_ops);
  	if (err < 0)
  		goto rtnl_link_failed;
e1a800022   Herbert Xu   gre: Add Transpar...
1636
1637
1638
  	err = rtnl_link_register(&ipgre_tap_ops);
  	if (err < 0)
  		goto tap_ops_failed;
c19e654dd   Herbert Xu   gre: Add netlink ...
1639
  out:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1640
  	return err;
c19e654dd   Herbert Xu   gre: Add netlink ...
1641

e1a800022   Herbert Xu   gre: Add Transpar...
1642
1643
  tap_ops_failed:
  	rtnl_link_unregister(&ipgre_link_ops);
c19e654dd   Herbert Xu   gre: Add netlink ...
1644
  rtnl_link_failed:
00959ade3   Dmitry Kozlov   PPTP: PPP over IP...
1645
  	gre_del_protocol(&ipgre_protocol, GREPROTO_CISCO);
c2892f027   Alexey Dobriyan   gre: fix netns vs...
1646
1647
  add_proto_failed:
  	unregister_pernet_device(&ipgre_net_ops);
c19e654dd   Herbert Xu   gre: Add netlink ...
1648
  	goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1649
  }
db44575f6   Alexey Kuznetsov   [NET]: fix oops a...
1650
  static void __exit ipgre_fini(void)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1651
  {
e1a800022   Herbert Xu   gre: Add Transpar...
1652
  	rtnl_link_unregister(&ipgre_tap_ops);
c19e654dd   Herbert Xu   gre: Add netlink ...
1653
  	rtnl_link_unregister(&ipgre_link_ops);
00959ade3   Dmitry Kozlov   PPTP: PPP over IP...
1654
  	if (gre_del_protocol(&ipgre_protocol, GREPROTO_CISCO) < 0)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1655
1656
  		printk(KERN_INFO "ipgre close: can't remove protocol
  ");
c2892f027   Alexey Dobriyan   gre: fix netns vs...
1657
  	unregister_pernet_device(&ipgre_net_ops);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1658
1659
1660
1661
1662
  }
  
  module_init(ipgre_init);
  module_exit(ipgre_fini);
  MODULE_LICENSE("GPL");
4d74f8ba1   Patrick McHardy   gre: minor cleanu...
1663
1664
  MODULE_ALIAS_RTNL_LINK("gre");
  MODULE_ALIAS_RTNL_LINK("gretap");
8909c9ad8   Vasiliy Kulikov   net: don't allow ...
1665
  MODULE_ALIAS_NETDEV("gre0");