Blame view

net/ipv6/ip6_gre.c 58.2 KB
2874c5fd2   Thomas Gleixner   treewide: Replace...
1
  // SPDX-License-Identifier: GPL-2.0-or-later
c12b395a4   xeb@mail.ru   gre: Support GRE ...
2
3
4
5
  /*
   *	GRE over IPv6 protocol decoder.
   *
   *	Authors: Dmitry Kozlov (xeb@mail.ru)
c12b395a4   xeb@mail.ru   gre: Support GRE ...
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
   */
  
  #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
  
  #include <linux/capability.h>
  #include <linux/module.h>
  #include <linux/types.h>
  #include <linux/kernel.h>
  #include <linux/slab.h>
  #include <linux/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>
c12b395a4   xeb@mail.ru   gre: Support GRE ...
22
23
24
25
26
27
28
29
30
31
32
33
34
  #include <linux/init.h>
  #include <linux/in6.h>
  #include <linux/inetdevice.h>
  #include <linux/igmp.h>
  #include <linux/netfilter_ipv4.h>
  #include <linux/etherdevice.h>
  #include <linux/if_ether.h>
  #include <linux/hash.h>
  #include <linux/if_tunnel.h>
  #include <linux/ip6_tunnel.h>
  
  #include <net/sock.h>
  #include <net/ip.h>
c54419321   Pravin B Shelar   GRE: Refactor GRE...
35
  #include <net/ip_tunnels.h>
c12b395a4   xeb@mail.ru   gre: Support GRE ...
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
  #include <net/icmp.h>
  #include <net/protocol.h>
  #include <net/addrconf.h>
  #include <net/arp.h>
  #include <net/checksum.h>
  #include <net/dsfield.h>
  #include <net/inet_ecn.h>
  #include <net/xfrm.h>
  #include <net/net_namespace.h>
  #include <net/netns/generic.h>
  #include <net/rtnetlink.h>
  
  #include <net/ipv6.h>
  #include <net/ip6_fib.h>
  #include <net/ip6_route.h>
  #include <net/ip6_tunnel.h>
308edfdf1   Tom Herbert   gre6: Cleanup GRE...
52
  #include <net/gre.h>
5a963eb61   William Tu   ip6_gre: Add ERSP...
53
  #include <net/erspan.h>
6712abc16   William Tu   ip6_gre: add ip6 ...
54
  #include <net/dst_metadata.h>
c12b395a4   xeb@mail.ru   gre: Support GRE ...
55

eccc1bb8d   stephen hemminger   tunnel: drop pack...
56
57
58
  static bool log_ecn_error = true;
  module_param(log_ecn_error, bool, 0644);
  MODULE_PARM_DESC(log_ecn_error, "Log packets received with corrupted ECN");
e87a8f24c   Jiri Kosina   net: resolve symb...
59
60
  #define IP6_GRE_HASH_SIZE_SHIFT  5
  #define IP6_GRE_HASH_SIZE (1 << IP6_GRE_HASH_SIZE_SHIFT)
c12b395a4   xeb@mail.ru   gre: Support GRE ...
61

c7d03a00b   Alexey Dobriyan   netns: make struc...
62
  static unsigned int ip6gre_net_id __read_mostly;
c12b395a4   xeb@mail.ru   gre: Support GRE ...
63
  struct ip6gre_net {
e87a8f24c   Jiri Kosina   net: resolve symb...
64
  	struct ip6_tnl __rcu *tunnels[4][IP6_GRE_HASH_SIZE];
c12b395a4   xeb@mail.ru   gre: Support GRE ...
65

6712abc16   William Tu   ip6_gre: add ip6 ...
66
  	struct ip6_tnl __rcu *collect_md_tun;
b80d0b93b   William Tu   net: ip6_gre: fix...
67
  	struct ip6_tnl __rcu *collect_md_tun_erspan;
c12b395a4   xeb@mail.ru   gre: Support GRE ...
68
69
70
71
  	struct net_device *fb_tunnel_dev;
  };
  
  static struct rtnl_link_ops ip6gre_link_ops __read_mostly;
22f08069e   Nicolas Dichtel   ip6gre: add x-net...
72
  static struct rtnl_link_ops ip6gre_tap_ops __read_mostly;
5a963eb61   William Tu   ip6_gre: Add ERSP...
73
  static struct rtnl_link_ops ip6erspan_tap_ops __read_mostly;
c12b395a4   xeb@mail.ru   gre: Support GRE ...
74
75
76
77
  static int ip6gre_tunnel_init(struct net_device *dev);
  static void ip6gre_tunnel_setup(struct net_device *dev);
  static void ip6gre_tunnel_link(struct ip6gre_net *ign, struct ip6_tnl *t);
  static void ip6gre_tnl_link_config(struct ip6_tnl *t, int set_mtu);
2d665034f   Petr Machata   net: ip6_gre: Fix...
78
  static void ip6erspan_tnl_link_config(struct ip6_tnl *t, int set_mtu);
c12b395a4   xeb@mail.ru   gre: Support GRE ...
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
  
  /* 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.
   */
e87a8f24c   Jiri Kosina   net: resolve symb...
97
  #define HASH_KEY(key) (((__force u32)key^((__force u32)key>>4))&(IP6_GRE_HASH_SIZE - 1))
c12b395a4   xeb@mail.ru   gre: Support GRE ...
98
99
100
  static u32 HASH_ADDR(const struct in6_addr *addr)
  {
  	u32 hash = ipv6_addr_hash(addr);
e87a8f24c   Jiri Kosina   net: resolve symb...
101
  	return hash_32(hash, IP6_GRE_HASH_SIZE_SHIFT);
c12b395a4   xeb@mail.ru   gre: Support GRE ...
102
103
104
105
106
107
  }
  
  #define tunnels_r_l	tunnels[3]
  #define tunnels_r	tunnels[2]
  #define tunnels_l	tunnels[1]
  #define tunnels_wc	tunnels[0]
c12b395a4   xeb@mail.ru   gre: Support GRE ...
108

c12b395a4   xeb@mail.ru   gre: Support GRE ...
109
110
111
112
113
114
115
116
117
118
119
120
  /* Given src, dst and key, find appropriate for input tunnel. */
  
  static struct ip6_tnl *ip6gre_tunnel_lookup(struct net_device *dev,
  		const struct in6_addr *remote, const struct in6_addr *local,
  		__be32 key, __be16 gre_proto)
  {
  	struct net *net = dev_net(dev);
  	int link = dev->ifindex;
  	unsigned int h0 = HASH_ADDR(remote);
  	unsigned int h1 = HASH_KEY(key);
  	struct ip6_tnl *t, *cand = NULL;
  	struct ip6gre_net *ign = net_generic(net, ip6gre_net_id);
5a963eb61   William Tu   ip6_gre: Add ERSP...
121
  	int dev_type = (gre_proto == htons(ETH_P_TEB) ||
3b04caab8   William Tu   ip6gre: add erspa...
122
123
  			gre_proto == htons(ETH_P_ERSPAN) ||
  			gre_proto == htons(ETH_P_ERSPAN2)) ?
c12b395a4   xeb@mail.ru   gre: Support GRE ...
124
125
  		       ARPHRD_ETHER : ARPHRD_IP6GRE;
  	int score, cand_score = 4;
dafabb659   Taehee Yoo   ip6_gre: fix use-...
126
  	struct net_device *ndev;
c12b395a4   xeb@mail.ru   gre: Support GRE ...
127

e086cadc0   Amerigo Wang   net: unify for_ea...
128
  	for_each_ip_tunnel_rcu(t, ign->tunnels_r_l[h0 ^ h1]) {
c12b395a4   xeb@mail.ru   gre: Support GRE ...
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
  		if (!ipv6_addr_equal(local, &t->parms.laddr) ||
  		    !ipv6_addr_equal(remote, &t->parms.raddr) ||
  		    key != t->parms.i_key ||
  		    !(t->dev->flags & IFF_UP))
  			continue;
  
  		if (t->dev->type != ARPHRD_IP6GRE &&
  		    t->dev->type != dev_type)
  			continue;
  
  		score = 0;
  		if (t->parms.link != link)
  			score |= 1;
  		if (t->dev->type != dev_type)
  			score |= 2;
  		if (score == 0)
  			return t;
  
  		if (score < cand_score) {
  			cand = t;
  			cand_score = score;
  		}
  	}
e086cadc0   Amerigo Wang   net: unify for_ea...
152
  	for_each_ip_tunnel_rcu(t, ign->tunnels_r[h0 ^ h1]) {
c12b395a4   xeb@mail.ru   gre: Support GRE ...
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
  		if (!ipv6_addr_equal(remote, &t->parms.raddr) ||
  		    key != t->parms.i_key ||
  		    !(t->dev->flags & IFF_UP))
  			continue;
  
  		if (t->dev->type != ARPHRD_IP6GRE &&
  		    t->dev->type != dev_type)
  			continue;
  
  		score = 0;
  		if (t->parms.link != link)
  			score |= 1;
  		if (t->dev->type != dev_type)
  			score |= 2;
  		if (score == 0)
  			return t;
  
  		if (score < cand_score) {
  			cand = t;
  			cand_score = score;
  		}
  	}
e086cadc0   Amerigo Wang   net: unify for_ea...
175
  	for_each_ip_tunnel_rcu(t, ign->tunnels_l[h1]) {
c12b395a4   xeb@mail.ru   gre: Support GRE ...
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
  		if ((!ipv6_addr_equal(local, &t->parms.laddr) &&
  			  (!ipv6_addr_equal(local, &t->parms.raddr) ||
  				 !ipv6_addr_is_multicast(local))) ||
  		    key != t->parms.i_key ||
  		    !(t->dev->flags & IFF_UP))
  			continue;
  
  		if (t->dev->type != ARPHRD_IP6GRE &&
  		    t->dev->type != dev_type)
  			continue;
  
  		score = 0;
  		if (t->parms.link != link)
  			score |= 1;
  		if (t->dev->type != dev_type)
  			score |= 2;
  		if (score == 0)
  			return t;
  
  		if (score < cand_score) {
  			cand = t;
  			cand_score = score;
  		}
  	}
e086cadc0   Amerigo Wang   net: unify for_ea...
200
  	for_each_ip_tunnel_rcu(t, ign->tunnels_wc[h1]) {
c12b395a4   xeb@mail.ru   gre: Support GRE ...
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
  		if (t->parms.i_key != key ||
  		    !(t->dev->flags & IFF_UP))
  			continue;
  
  		if (t->dev->type != ARPHRD_IP6GRE &&
  		    t->dev->type != dev_type)
  			continue;
  
  		score = 0;
  		if (t->parms.link != link)
  			score |= 1;
  		if (t->dev->type != dev_type)
  			score |= 2;
  		if (score == 0)
  			return t;
  
  		if (score < cand_score) {
  			cand = t;
  			cand_score = score;
  		}
  	}
53b24b8f9   Ian Morris   ipv6: coding styl...
222
  	if (cand)
c12b395a4   xeb@mail.ru   gre: Support GRE ...
223
  		return cand;
b80d0b93b   William Tu   net: ip6_gre: fix...
224
225
226
227
228
  	if (gre_proto == htons(ETH_P_ERSPAN) ||
  	    gre_proto == htons(ETH_P_ERSPAN2))
  		t = rcu_dereference(ign->collect_md_tun_erspan);
  	else
  		t = rcu_dereference(ign->collect_md_tun);
6712abc16   William Tu   ip6_gre: add ip6 ...
229
230
  	if (t && t->dev->flags & IFF_UP)
  		return t;
dafabb659   Taehee Yoo   ip6_gre: fix use-...
231
232
233
  	ndev = READ_ONCE(ign->fb_tunnel_dev);
  	if (ndev && ndev->flags & IFF_UP)
  		return netdev_priv(ndev);
c12b395a4   xeb@mail.ru   gre: Support GRE ...
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
  
  	return NULL;
  }
  
  static struct ip6_tnl __rcu **__ip6gre_bucket(struct ip6gre_net *ign,
  		const struct __ip6_tnl_parm *p)
  {
  	const struct in6_addr *remote = &p->raddr;
  	const struct in6_addr *local = &p->laddr;
  	unsigned int h = HASH_KEY(p->i_key);
  	int prio = 0;
  
  	if (!ipv6_addr_any(local))
  		prio |= 1;
  	if (!ipv6_addr_any(remote) && !ipv6_addr_is_multicast(remote)) {
  		prio |= 2;
  		h ^= HASH_ADDR(remote);
  	}
  
  	return &ign->tunnels[prio][h];
  }
b80d0b93b   William Tu   net: ip6_gre: fix...
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
  static void ip6gre_tunnel_link_md(struct ip6gre_net *ign, struct ip6_tnl *t)
  {
  	if (t->parms.collect_md)
  		rcu_assign_pointer(ign->collect_md_tun, t);
  }
  
  static void ip6erspan_tunnel_link_md(struct ip6gre_net *ign, struct ip6_tnl *t)
  {
  	if (t->parms.collect_md)
  		rcu_assign_pointer(ign->collect_md_tun_erspan, t);
  }
  
  static void ip6gre_tunnel_unlink_md(struct ip6gre_net *ign, struct ip6_tnl *t)
  {
  	if (t->parms.collect_md)
  		rcu_assign_pointer(ign->collect_md_tun, NULL);
  }
  
  static void ip6erspan_tunnel_unlink_md(struct ip6gre_net *ign,
  				       struct ip6_tnl *t)
  {
  	if (t->parms.collect_md)
  		rcu_assign_pointer(ign->collect_md_tun_erspan, NULL);
  }
c12b395a4   xeb@mail.ru   gre: Support GRE ...
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
  static inline struct ip6_tnl __rcu **ip6gre_bucket(struct ip6gre_net *ign,
  		const struct ip6_tnl *t)
  {
  	return __ip6gre_bucket(ign, &t->parms);
  }
  
  static void ip6gre_tunnel_link(struct ip6gre_net *ign, struct ip6_tnl *t)
  {
  	struct ip6_tnl __rcu **tp = ip6gre_bucket(ign, t);
  
  	rcu_assign_pointer(t->next, rtnl_dereference(*tp));
  	rcu_assign_pointer(*tp, t);
  }
  
  static void ip6gre_tunnel_unlink(struct ip6gre_net *ign, struct ip6_tnl *t)
  {
  	struct ip6_tnl __rcu **tp;
  	struct ip6_tnl *iter;
  
  	for (tp = ip6gre_bucket(ign, t);
  	     (iter = rtnl_dereference(*tp)) != NULL;
  	     tp = &iter->next) {
  		if (t == iter) {
  			rcu_assign_pointer(*tp, t->next);
  			break;
  		}
  	}
  }
  
  static struct ip6_tnl *ip6gre_tunnel_find(struct net *net,
  					   const struct __ip6_tnl_parm *parms,
  					   int type)
  {
  	const struct in6_addr *remote = &parms->raddr;
  	const struct in6_addr *local = &parms->laddr;
  	__be32 key = parms->i_key;
  	int link = parms->link;
  	struct ip6_tnl *t;
  	struct ip6_tnl __rcu **tp;
  	struct ip6gre_net *ign = net_generic(net, ip6gre_net_id);
  
  	for (tp = __ip6gre_bucket(ign, parms);
  	     (t = rtnl_dereference(*tp)) != NULL;
  	     tp = &t->next)
  		if (ipv6_addr_equal(local, &t->parms.laddr) &&
  		    ipv6_addr_equal(remote, &t->parms.raddr) &&
  		    key == t->parms.i_key &&
  		    link == t->parms.link &&
  		    type == t->dev->type)
  			break;
  
  	return t;
  }
  
  static struct ip6_tnl *ip6gre_tunnel_locate(struct net *net,
  		const struct __ip6_tnl_parm *parms, int create)
  {
  	struct ip6_tnl *t, *nt;
  	struct net_device *dev;
  	char name[IFNAMSIZ];
  	struct ip6gre_net *ign = net_generic(net, ip6gre_net_id);
  
  	t = ip6gre_tunnel_find(net, parms, ARPHRD_IP6GRE);
cd0a0bd9b   Steffen Klassert   ip6_gre: Return a...
342
343
  	if (t && create)
  		return NULL;
c12b395a4   xeb@mail.ru   gre: Support GRE ...
344
345
  	if (t || !create)
  		return t;
5f42df013   Eric Dumazet   ip6_gre: better v...
346
347
348
  	if (parms->name[0]) {
  		if (!dev_valid_name(parms->name))
  			return NULL;
c12b395a4   xeb@mail.ru   gre: Support GRE ...
349
  		strlcpy(name, parms->name, IFNAMSIZ);
5f42df013   Eric Dumazet   ip6_gre: better v...
350
  	} else {
c12b395a4   xeb@mail.ru   gre: Support GRE ...
351
  		strcpy(name, "ip6gre%d");
5f42df013   Eric Dumazet   ip6_gre: better v...
352
  	}
c835a6773   Tom Gundersen   net: set name_ass...
353
354
  	dev = alloc_netdev(sizeof(*t), name, NET_NAME_UNKNOWN,
  			   ip6gre_tunnel_setup);
c12b395a4   xeb@mail.ru   gre: Support GRE ...
355
356
357
358
359
360
361
362
363
364
  	if (!dev)
  		return NULL;
  
  	dev_net_set(dev, net);
  
  	nt = netdev_priv(dev);
  	nt->parms = *parms;
  	dev->rtnl_link_ops = &ip6gre_link_ops;
  
  	nt->dev = dev;
0bd876282   Nicolas Dichtel   ip6tnl: add x-net...
365
  	nt->net = dev_net(dev);
c12b395a4   xeb@mail.ru   gre: Support GRE ...
366
367
368
  
  	if (register_netdevice(dev) < 0)
  		goto failed_free;
128bb975d   Alexey Kodanev   ip6_gre: init dev...
369
  	ip6gre_tnl_link_config(nt, 1);
c12b395a4   xeb@mail.ru   gre: Support GRE ...
370
  	/* Can use a lockless transmit, unless we generate output sequences */
b45bd1d78   Tom Herbert   ip6_gre: Use corr...
371
  	if (!(nt->parms.o_flags & TUNNEL_SEQ))
c12b395a4   xeb@mail.ru   gre: Support GRE ...
372
373
374
375
376
377
378
379
380
381
  		dev->features |= NETIF_F_LLTX;
  
  	dev_hold(dev);
  	ip6gre_tunnel_link(ign, nt);
  	return nt;
  
  failed_free:
  	free_netdev(dev);
  	return NULL;
  }
b80d0b93b   William Tu   net: ip6_gre: fix...
382
383
384
385
386
387
388
389
390
391
  static void ip6erspan_tunnel_uninit(struct net_device *dev)
  {
  	struct ip6_tnl *t = netdev_priv(dev);
  	struct ip6gre_net *ign = net_generic(t->net, ip6gre_net_id);
  
  	ip6erspan_tunnel_unlink_md(ign, t);
  	ip6gre_tunnel_unlink(ign, t);
  	dst_cache_reset(&t->dst_cache);
  	dev_put(dev);
  }
c12b395a4   xeb@mail.ru   gre: Support GRE ...
392
393
  static void ip6gre_tunnel_uninit(struct net_device *dev)
  {
22f08069e   Nicolas Dichtel   ip6gre: add x-net...
394
395
  	struct ip6_tnl *t = netdev_priv(dev);
  	struct ip6gre_net *ign = net_generic(t->net, ip6gre_net_id);
c12b395a4   xeb@mail.ru   gre: Support GRE ...
396

b80d0b93b   William Tu   net: ip6_gre: fix...
397
  	ip6gre_tunnel_unlink_md(ign, t);
22f08069e   Nicolas Dichtel   ip6gre: add x-net...
398
  	ip6gre_tunnel_unlink(ign, t);
dafabb659   Taehee Yoo   ip6_gre: fix use-...
399
400
  	if (ign->fb_tunnel_dev == dev)
  		WRITE_ONCE(ign->fb_tunnel_dev, NULL);
607f725f6   Paolo Abeni   net: replace dst_...
401
  	dst_cache_reset(&t->dst_cache);
c12b395a4   xeb@mail.ru   gre: Support GRE ...
402
403
  	dev_put(dev);
  }
32bbd8793   Stefano Brivio   net: Convert prot...
404
  static int ip6gre_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
7892032cf   Eric Dumazet   ip6_gre: fix ip6g...
405
  		       u8 type, u8 code, int offset, __be32 info)
c12b395a4   xeb@mail.ru   gre: Support GRE ...
406
  {
929fc0327   Xin Long   ip6_gre: add the ...
407
  	struct net *net = dev_net(skb->dev);
7892032cf   Eric Dumazet   ip6_gre: fix ip6g...
408
  	const struct ipv6hdr *ipv6h;
a82738adf   Haishuang Yan   ip6_gre: simplify...
409
  	struct tnl_ptk_info tpi;
c12b395a4   xeb@mail.ru   gre: Support GRE ...
410
  	struct ip6_tnl *t;
c12b395a4   xeb@mail.ru   gre: Support GRE ...
411

a82738adf   Haishuang Yan   ip6_gre: simplify...
412
413
  	if (gre_parse_header(skb, &tpi, NULL, htons(ETH_P_IPV6),
  			     offset) < 0)
32bbd8793   Stefano Brivio   net: Convert prot...
414
  		return -EINVAL;
c12b395a4   xeb@mail.ru   gre: Support GRE ...
415

b87fb39e3   Eric Dumazet   ipv6: gre: fix ip...
416
  	ipv6h = (const struct ipv6hdr *)skb->data;
c12b395a4   xeb@mail.ru   gre: Support GRE ...
417
  	t = ip6gre_tunnel_lookup(skb->dev, &ipv6h->daddr, &ipv6h->saddr,
a82738adf   Haishuang Yan   ip6_gre: simplify...
418
  				 tpi.key, tpi.proto);
63159f29b   Ian Morris   ipv6: coding styl...
419
  	if (!t)
32bbd8793   Stefano Brivio   net: Convert prot...
420
  		return -ENOENT;
c12b395a4   xeb@mail.ru   gre: Support GRE ...
421
422
  
  	switch (type) {
c12b395a4   xeb@mail.ru   gre: Support GRE ...
423
  	case ICMPV6_DEST_UNREACH:
a46496ce3   Matt Bennett   ip6_gre: Reduce l...
424
425
426
  		net_dbg_ratelimited("%s: Path to destination invalid or inactive!
  ",
  				    t->parms.name);
f8d20b46c   Xin Long   ip6_gre: only inc...
427
428
  		if (code != ICMPV6_PORT_UNREACH)
  			break;
32bbd8793   Stefano Brivio   net: Convert prot...
429
  		return 0;
c12b395a4   xeb@mail.ru   gre: Support GRE ...
430
431
  	case ICMPV6_TIME_EXCEED:
  		if (code == ICMPV6_EXC_HOPLIMIT) {
a46496ce3   Matt Bennett   ip6_gre: Reduce l...
432
433
434
  			net_dbg_ratelimited("%s: Too small hop limit or routing loop in tunnel!
  ",
  					    t->parms.name);
f8d20b46c   Xin Long   ip6_gre: only inc...
435
  			break;
c12b395a4   xeb@mail.ru   gre: Support GRE ...
436
  		}
32bbd8793   Stefano Brivio   net: Convert prot...
437
  		return 0;
46d30cb10   Kees Cook   net: ip6_gre: Dis...
438
439
440
  	case ICMPV6_PARAMPROB: {
  		struct ipv6_tlv_tnl_enc_lim *tel;
  		__u32 teli;
c12b395a4   xeb@mail.ru   gre: Support GRE ...
441
442
443
  		teli = 0;
  		if (code == ICMPV6_HDR_FIELD)
  			teli = ip6_tnl_parse_tlv_enc_lim(skb, skb->data);
d1e158e2d   Sabrina Dubroca   ip6_gre: fix endi...
444
  		if (teli && teli == be32_to_cpu(info) - 2) {
c12b395a4   xeb@mail.ru   gre: Support GRE ...
445
446
  			tel = (struct ipv6_tlv_tnl_enc_lim *) &skb->data[teli];
  			if (tel->encap_limit == 0) {
a46496ce3   Matt Bennett   ip6_gre: Reduce l...
447
448
449
  				net_dbg_ratelimited("%s: Too small encapsulation limit or routing loop in tunnel!
  ",
  						    t->parms.name);
c12b395a4   xeb@mail.ru   gre: Support GRE ...
450
451
  			}
  		} else {
a46496ce3   Matt Bennett   ip6_gre: Reduce l...
452
453
454
  			net_dbg_ratelimited("%s: Recipient unable to parse tunneled packet!
  ",
  					    t->parms.name);
c12b395a4   xeb@mail.ru   gre: Support GRE ...
455
  		}
32bbd8793   Stefano Brivio   net: Convert prot...
456
  		return 0;
46d30cb10   Kees Cook   net: ip6_gre: Dis...
457
  	}
c12b395a4   xeb@mail.ru   gre: Support GRE ...
458
  	case ICMPV6_PKT_TOOBIG:
fe1a4ca0a   Xin Long   ip6_gre: process ...
459
  		ip6_update_pmtu(skb, net, info, 0, 0, sock_net_uid(net, NULL));
32bbd8793   Stefano Brivio   net: Convert prot...
460
  		return 0;
929fc0327   Xin Long   ip6_gre: add the ...
461
462
463
  	case NDISC_REDIRECT:
  		ip6_redirect(skb, net, skb->dev->ifindex, 0,
  			     sock_net_uid(net, NULL));
32bbd8793   Stefano Brivio   net: Convert prot...
464
  		return 0;
c12b395a4   xeb@mail.ru   gre: Support GRE ...
465
466
467
468
469
470
471
  	}
  
  	if (time_before(jiffies, t->err_time + IP6TUNNEL_ERR_TIMEO))
  		t->err_count++;
  	else
  		t->err_count = 1;
  	t->err_time = jiffies;
32bbd8793   Stefano Brivio   net: Convert prot...
472
473
  
  	return 0;
c12b395a4   xeb@mail.ru   gre: Support GRE ...
474
  }
308edfdf1   Tom Herbert   gre6: Cleanup GRE...
475
  static int ip6gre_rcv(struct sk_buff *skb, const struct tnl_ptk_info *tpi)
c12b395a4   xeb@mail.ru   gre: Support GRE ...
476
477
  {
  	const struct ipv6hdr *ipv6h;
c12b395a4   xeb@mail.ru   gre: Support GRE ...
478
  	struct ip6_tnl *tunnel;
c12b395a4   xeb@mail.ru   gre: Support GRE ...
479
480
  
  	ipv6h = ipv6_hdr(skb);
c12b395a4   xeb@mail.ru   gre: Support GRE ...
481
  	tunnel = ip6gre_tunnel_lookup(skb->dev,
308edfdf1   Tom Herbert   gre6: Cleanup GRE...
482
483
  				      &ipv6h->saddr, &ipv6h->daddr, tpi->key,
  				      tpi->proto);
c12b395a4   xeb@mail.ru   gre: Support GRE ...
484
  	if (tunnel) {
6712abc16   William Tu   ip6_gre: add ip6 ...
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
  		if (tunnel->parms.collect_md) {
  			struct metadata_dst *tun_dst;
  			__be64 tun_id;
  			__be16 flags;
  
  			flags = tpi->flags;
  			tun_id = key32_to_tunnel_id(tpi->key);
  
  			tun_dst = ipv6_tun_rx_dst(skb, flags, tun_id, 0);
  			if (!tun_dst)
  				return PACKET_REJECT;
  
  			ip6_tnl_rcv(tunnel, skb, tpi, tun_dst, log_ecn_error);
  		} else {
  			ip6_tnl_rcv(tunnel, skb, tpi, NULL, log_ecn_error);
  		}
c12b395a4   xeb@mail.ru   gre: Support GRE ...
501

308edfdf1   Tom Herbert   gre6: Cleanup GRE...
502
503
  		return PACKET_RCVD;
  	}
eccc1bb8d   stephen hemminger   tunnel: drop pack...
504

308edfdf1   Tom Herbert   gre6: Cleanup GRE...
505
506
  	return PACKET_REJECT;
  }
eccc1bb8d   stephen hemminger   tunnel: drop pack...
507

a057fed33   Lorenzo Bianconi   net: ip6_gre: rem...
508
  static int ip6erspan_rcv(struct sk_buff *skb,
2a3cabae4   Lorenzo Bianconi   net: ip6_gre: fix...
509
510
  			 struct tnl_ptk_info *tpi,
  			 int gre_hdr_len)
5a963eb61   William Tu   ip6_gre: Add ERSP...
511
  {
1d7e2ed22   William Tu   net: erspan: refa...
512
  	struct erspan_base_hdr *ershdr;
5a963eb61   William Tu   ip6_gre: Add ERSP...
513
  	const struct ipv6hdr *ipv6h;
3df192830   William Tu   net: erspan: fix ...
514
  	struct erspan_md2 *md2;
5a963eb61   William Tu   ip6_gre: Add ERSP...
515
  	struct ip6_tnl *tunnel;
1d7e2ed22   William Tu   net: erspan: refa...
516
  	u8 ver;
5a963eb61   William Tu   ip6_gre: Add ERSP...
517

293a1991c   Haishuang Yan   ip6_gre: fix a po...
518
519
  	ipv6h = ipv6_hdr(skb);
  	ershdr = (struct erspan_base_hdr *)skb->data;
c69de58ba   William Tu   net: erspan: use ...
520
  	ver = ershdr->ver;
5a963eb61   William Tu   ip6_gre: Add ERSP...
521
522
523
524
525
  
  	tunnel = ip6gre_tunnel_lookup(skb->dev,
  				      &ipv6h->saddr, &ipv6h->daddr, tpi->key,
  				      tpi->proto);
  	if (tunnel) {
1d7e2ed22   William Tu   net: erspan: refa...
526
527
528
  		int len = erspan_hdr_len(ver);
  
  		if (unlikely(!pskb_may_pull(skb, len)))
ae3e13373   William Tu   net: erspan: fix ...
529
  			return PACKET_REJECT;
1d7e2ed22   William Tu   net: erspan: refa...
530
531
  
  		if (__iptunnel_pull_header(skb, len,
5a963eb61   William Tu   ip6_gre: Add ERSP...
532
533
534
  					   htons(ETH_P_TEB),
  					   false, false) < 0)
  			return PACKET_REJECT;
ef7baf5e0   William Tu   ip6_gre: add ip6 ...
535
  		if (tunnel->parms.collect_md) {
2a3cabae4   Lorenzo Bianconi   net: ip6_gre: fix...
536
  			struct erspan_metadata *pkt_md, *md;
ef7baf5e0   William Tu   ip6_gre: add ip6 ...
537
538
  			struct metadata_dst *tun_dst;
  			struct ip_tunnel_info *info;
2a3cabae4   Lorenzo Bianconi   net: ip6_gre: fix...
539
  			unsigned char *gh;
ef7baf5e0   William Tu   ip6_gre: add ip6 ...
540
541
542
543
544
545
546
547
548
549
550
  			__be64 tun_id;
  			__be16 flags;
  
  			tpi->flags |= TUNNEL_KEY;
  			flags = tpi->flags;
  			tun_id = key32_to_tunnel_id(tpi->key);
  
  			tun_dst = ipv6_tun_rx_dst(skb, flags, tun_id,
  						  sizeof(*md));
  			if (!tun_dst)
  				return PACKET_REJECT;
2a3cabae4   Lorenzo Bianconi   net: ip6_gre: fix...
551
552
553
554
555
556
557
558
  			/* skb can be uncloned in __iptunnel_pull_header, so
  			 * old pkt_md is no longer valid and we need to reset
  			 * it
  			 */
  			gh = skb_network_header(skb) +
  			     skb_network_header_len(skb);
  			pkt_md = (struct erspan_metadata *)(gh + gre_hdr_len +
  							    sizeof(*ershdr));
ef7baf5e0   William Tu   ip6_gre: add ip6 ...
559
560
  			info = &tun_dst->u.tun_info;
  			md = ip_tunnel_info_opts(info);
94d7d8f29   William Tu   ip6_gre: add ersp...
561
  			md->version = ver;
3df192830   William Tu   net: erspan: fix ...
562
563
564
  			md2 = &md->u.md2;
  			memcpy(md2, pkt_md, ver == 1 ? ERSPAN_V1_MDSIZE :
  						       ERSPAN_V2_MDSIZE);
ef7baf5e0   William Tu   ip6_gre: add ip6 ...
565
566
567
568
569
570
  			info->key.tun_flags |= TUNNEL_ERSPAN_OPT;
  			info->options_len = sizeof(*md);
  
  			ip6_tnl_rcv(tunnel, skb, tpi, tun_dst, log_ecn_error);
  
  		} else {
ef7baf5e0   William Tu   ip6_gre: add ip6 ...
571
572
  			ip6_tnl_rcv(tunnel, skb, tpi, NULL, log_ecn_error);
  		}
5a963eb61   William Tu   ip6_gre: Add ERSP...
573
574
575
576
577
578
  
  		return PACKET_RCVD;
  	}
  
  	return PACKET_REJECT;
  }
308edfdf1   Tom Herbert   gre6: Cleanup GRE...
579
580
581
582
583
  static int gre_rcv(struct sk_buff *skb)
  {
  	struct tnl_ptk_info tpi;
  	bool csum_err = false;
  	int hdr_len;
eccc1bb8d   stephen hemminger   tunnel: drop pack...
584

e582615ad   Eric Dumazet   gre: fix error ha...
585
  	hdr_len = gre_parse_header(skb, &tpi, &csum_err, htons(ETH_P_IPV6), 0);
f132ae7c4   Jiri Benc   gre: change gre_p...
586
  	if (hdr_len < 0)
308edfdf1   Tom Herbert   gre6: Cleanup GRE...
587
  		goto drop;
c12b395a4   xeb@mail.ru   gre: Support GRE ...
588

308edfdf1   Tom Herbert   gre6: Cleanup GRE...
589
590
  	if (iptunnel_pull_header(skb, hdr_len, tpi.proto, false))
  		goto drop;
c12b395a4   xeb@mail.ru   gre: Support GRE ...
591

94d7d8f29   William Tu   ip6_gre: add ersp...
592
593
  	if (unlikely(tpi.proto == htons(ETH_P_ERSPAN) ||
  		     tpi.proto == htons(ETH_P_ERSPAN2))) {
2a3cabae4   Lorenzo Bianconi   net: ip6_gre: fix...
594
  		if (ip6erspan_rcv(skb, &tpi, hdr_len) == PACKET_RCVD)
5a963eb61   William Tu   ip6_gre: Add ERSP...
595
  			return 0;
a7343211f   Haishuang Yan   ip6_gre: fix erro...
596
  		goto out;
5a963eb61   William Tu   ip6_gre: Add ERSP...
597
  	}
308edfdf1   Tom Herbert   gre6: Cleanup GRE...
598
  	if (ip6gre_rcv(skb, &tpi) == PACKET_RCVD)
c12b395a4   xeb@mail.ru   gre: Support GRE ...
599
  		return 0;
c12b395a4   xeb@mail.ru   gre: Support GRE ...
600

a7343211f   Haishuang Yan   ip6_gre: fix erro...
601
  out:
308edfdf1   Tom Herbert   gre6: Cleanup GRE...
602
  	icmpv6_send(skb, ICMPV6_DEST_UNREACH, ICMPV6_PORT_UNREACH, 0);
c12b395a4   xeb@mail.ru   gre: Support GRE ...
603
  drop:
c12b395a4   xeb@mail.ru   gre: Support GRE ...
604
605
606
  	kfree_skb(skb);
  	return 0;
  }
b05229f44   Tom Herbert   gre6: Cleanup GRE...
607
  static int gre_handle_offloads(struct sk_buff *skb, bool csum)
c12b395a4   xeb@mail.ru   gre: Support GRE ...
608
  {
b05229f44   Tom Herbert   gre6: Cleanup GRE...
609
610
  	return iptunnel_handle_offloads(skb,
  					csum ? SKB_GSO_GRE_CSUM : SKB_GSO_GRE);
c12b395a4   xeb@mail.ru   gre: Support GRE ...
611
  }
898b29798   William Tu   ip6_gre: Refactor...
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
  static void prepare_ip6gre_xmit_ipv4(struct sk_buff *skb,
  				     struct net_device *dev,
  				     struct flowi6 *fl6, __u8 *dsfield,
  				     int *encap_limit)
  {
  	const struct iphdr *iph = ip_hdr(skb);
  	struct ip6_tnl *t = netdev_priv(dev);
  
  	if (!(t->parms.flags & IP6_TNL_F_IGN_ENCAP_LIMIT))
  		*encap_limit = t->parms.encap_limit;
  
  	memcpy(fl6, &t->fl.u.ip6, sizeof(*fl6));
  
  	if (t->parms.flags & IP6_TNL_F_USE_ORIG_TCLASS)
  		*dsfield = ipv4_get_dsfield(iph);
  	else
  		*dsfield = ip6_tclass(t->parms.flowinfo);
  
  	if (t->parms.flags & IP6_TNL_F_USE_ORIG_FWMARK)
  		fl6->flowi6_mark = skb->mark;
  	else
  		fl6->flowi6_mark = t->parms.fwmark;
  
  	fl6->flowi6_uid = sock_net_uid(dev_net(dev), NULL);
  }
  
  static int prepare_ip6gre_xmit_ipv6(struct sk_buff *skb,
  				    struct net_device *dev,
  				    struct flowi6 *fl6, __u8 *dsfield,
  				    int *encap_limit)
  {
3bc817d66   Haishuang Yan   ip6_gre: reload i...
643
  	struct ipv6hdr *ipv6h;
898b29798   William Tu   ip6_gre: Refactor...
644
645
646
647
648
  	struct ip6_tnl *t = netdev_priv(dev);
  	__u16 offset;
  
  	offset = ip6_tnl_parse_tlv_enc_lim(skb, skb_network_header(skb));
  	/* ip6_tnl_parse_tlv_enc_lim() might have reallocated skb->head */
3bc817d66   Haishuang Yan   ip6_gre: reload i...
649
  	ipv6h = ipv6_hdr(skb);
898b29798   William Tu   ip6_gre: Refactor...
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
  
  	if (offset > 0) {
  		struct ipv6_tlv_tnl_enc_lim *tel;
  
  		tel = (struct ipv6_tlv_tnl_enc_lim *)&skb_network_header(skb)[offset];
  		if (tel->encap_limit == 0) {
  			icmpv6_send(skb, ICMPV6_PARAMPROB,
  				    ICMPV6_HDR_FIELD, offset + 2);
  			return -1;
  		}
  		*encap_limit = tel->encap_limit - 1;
  	} else if (!(t->parms.flags & IP6_TNL_F_IGN_ENCAP_LIMIT)) {
  		*encap_limit = t->parms.encap_limit;
  	}
  
  	memcpy(fl6, &t->fl.u.ip6, sizeof(*fl6));
  
  	if (t->parms.flags & IP6_TNL_F_USE_ORIG_TCLASS)
  		*dsfield = ipv6_get_dsfield(ipv6h);
  	else
  		*dsfield = ip6_tclass(t->parms.flowinfo);
  
  	if (t->parms.flags & IP6_TNL_F_USE_ORIG_FLOWLABEL)
  		fl6->flowlabel |= ip6_flowlabel(ipv6h);
  
  	if (t->parms.flags & IP6_TNL_F_USE_ORIG_FWMARK)
  		fl6->flowi6_mark = skb->mark;
  	else
  		fl6->flowi6_mark = t->parms.fwmark;
  
  	fl6->flowi6_uid = sock_net_uid(dev_net(dev), NULL);
  
  	return 0;
  }
e5f7e211b   Davide Caratti   ip6gre: avoid tx_...
684
685
686
687
688
689
690
691
692
693
  static struct ip_tunnel_info *skb_tunnel_info_txcheck(struct sk_buff *skb)
  {
  	struct ip_tunnel_info *tun_info;
  
  	tun_info = skb_tunnel_info(skb);
  	if (unlikely(!tun_info || !(tun_info->mode & IP_TUNNEL_INFO_TX)))
  		return ERR_PTR(-EINVAL);
  
  	return tun_info;
  }
b05229f44   Tom Herbert   gre6: Cleanup GRE...
694
695
696
697
  static netdev_tx_t __gre6_xmit(struct sk_buff *skb,
  			       struct net_device *dev, __u8 dsfield,
  			       struct flowi6 *fl6, int encap_limit,
  			       __u32 *pmtu, __be16 proto)
c12b395a4   xeb@mail.ru   gre: Support GRE ...
698
  {
c12b395a4   xeb@mail.ru   gre: Support GRE ...
699
  	struct ip6_tnl *tunnel = netdev_priv(dev);
8aec4959d   Xin Long   ip6_gre: update d...
700
  	__be16 protocol;
c12b395a4   xeb@mail.ru   gre: Support GRE ...
701
702
703
  
  	if (dev->type == ARPHRD_ETHER)
  		IPCB(skb)->flags = 0;
b05229f44   Tom Herbert   gre6: Cleanup GRE...
704
705
706
  	if (dev->header_ops && dev->type == ARPHRD_IP6GRE)
  		fl6->daddr = ((struct ipv6hdr *)skb->data)->daddr;
  	else
c12b395a4   xeb@mail.ru   gre: Support GRE ...
707
  		fl6->daddr = tunnel->parms.raddr;
c12b395a4   xeb@mail.ru   gre: Support GRE ...
708

01b8d064d   Petr Machata   net: ip6_gre: Req...
709
710
  	if (skb_cow_head(skb, dev->needed_headroom ?: tunnel->hlen))
  		return -ENOMEM;
b05229f44   Tom Herbert   gre6: Cleanup GRE...
711
  	/* Push GRE header. */
8aec4959d   Xin Long   ip6_gre: update d...
712
  	protocol = (dev->type == ARPHRD_ETHER) ? htons(ETH_P_TEB) : proto;
6712abc16   William Tu   ip6_gre: add ip6 ...
713
714
715
716
717
  
  	if (tunnel->parms.collect_md) {
  		struct ip_tunnel_info *tun_info;
  		const struct ip_tunnel_key *key;
  		__be16 flags;
e5f7e211b   Davide Caratti   ip6gre: avoid tx_...
718
719
720
  		tun_info = skb_tunnel_info_txcheck(skb);
  		if (IS_ERR(tun_info) ||
  		    unlikely(ip_tunnel_info_af(tun_info) != AF_INET6))
6712abc16   William Tu   ip6_gre: add ip6 ...
721
722
723
724
725
726
727
728
729
730
  			return -EINVAL;
  
  		key = &tun_info->key;
  		memset(fl6, 0, sizeof(*fl6));
  		fl6->flowi6_proto = IPPROTO_GRE;
  		fl6->daddr = key->u.ipv6.dst;
  		fl6->flowlabel = key->label;
  		fl6->flowi6_uid = sock_net_uid(dev_net(dev), NULL);
  
  		dsfield = key->tos;
77a5196a8   William Tu   gre: add sequence...
731
732
  		flags = key->tun_flags &
  			(TUNNEL_CSUM | TUNNEL_KEY | TUNNEL_SEQ);
6712abc16   William Tu   ip6_gre: add ip6 ...
733
734
735
736
  		tunnel->tun_hlen = gre_calc_hlen(flags);
  
  		gre_build_header(skb, tunnel->tun_hlen,
  				 flags, protocol,
77a5196a8   William Tu   gre: add sequence...
737
  				 tunnel_id_to_key32(tun_info->key.tun_id),
157463941   Colin Ian King   gre: fix TUNNEL_S...
738
  				 (flags & TUNNEL_SEQ) ? htonl(tunnel->o_seqno++)
77a5196a8   William Tu   gre: add sequence...
739
  						      : 0);
6712abc16   William Tu   ip6_gre: add ip6 ...
740
741
  
  	} else {
77a5196a8   William Tu   gre: add sequence...
742
743
  		if (tunnel->parms.o_flags & TUNNEL_SEQ)
  			tunnel->o_seqno++;
6712abc16   William Tu   ip6_gre: add ip6 ...
744
745
746
747
  		gre_build_header(skb, tunnel->tun_hlen, tunnel->parms.o_flags,
  				 protocol, tunnel->parms.o_key,
  				 htonl(tunnel->o_seqno));
  	}
c12b395a4   xeb@mail.ru   gre: Support GRE ...
748

b05229f44   Tom Herbert   gre6: Cleanup GRE...
749
750
  	return ip6_tnl_xmit(skb, dev, dsfield, fl6, encap_limit, pmtu,
  			    NEXTHDR_GRE);
c12b395a4   xeb@mail.ru   gre: Support GRE ...
751
752
753
754
755
  }
  
  static inline int ip6gre_xmit_ipv4(struct sk_buff *skb, struct net_device *dev)
  {
  	struct ip6_tnl *t = netdev_priv(dev);
c12b395a4   xeb@mail.ru   gre: Support GRE ...
756
757
  	int encap_limit = -1;
  	struct flowi6 fl6;
6712abc16   William Tu   ip6_gre: add ip6 ...
758
  	__u8 dsfield = 0;
c12b395a4   xeb@mail.ru   gre: Support GRE ...
759
760
  	__u32 mtu;
  	int err;
5146d1f15   Bernie Harris   tunnel: Clear IPC...
761
  	memset(&(IPCB(skb)->opt), 0, sizeof(IPCB(skb)->opt));
6712abc16   William Tu   ip6_gre: add ip6 ...
762
763
764
  	if (!t->parms.collect_md)
  		prepare_ip6gre_xmit_ipv4(skb, dev, &fl6,
  					 &dsfield, &encap_limit);
e2d118a1c   Lorenzo Colitti   net: inet: Suppor...
765

b05229f44   Tom Herbert   gre6: Cleanup GRE...
766
767
768
769
770
771
  	err = gre_handle_offloads(skb, !!(t->parms.o_flags & TUNNEL_CSUM));
  	if (err)
  		return -1;
  
  	err = __gre6_xmit(skb, dev, dsfield, &fl6, encap_limit, &mtu,
  			  skb->protocol);
c12b395a4   xeb@mail.ru   gre: Support GRE ...
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
  	if (err != 0) {
  		/* XXX: send ICMP error even if DF is not set. */
  		if (err == -EMSGSIZE)
  			icmp_send(skb, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED,
  				  htonl(mtu));
  		return -1;
  	}
  
  	return 0;
  }
  
  static inline int ip6gre_xmit_ipv6(struct sk_buff *skb, struct net_device *dev)
  {
  	struct ip6_tnl *t = netdev_priv(dev);
  	struct ipv6hdr *ipv6h = ipv6_hdr(skb);
  	int encap_limit = -1;
c12b395a4   xeb@mail.ru   gre: Support GRE ...
788
  	struct flowi6 fl6;
6712abc16   William Tu   ip6_gre: add ip6 ...
789
  	__u8 dsfield = 0;
c12b395a4   xeb@mail.ru   gre: Support GRE ...
790
791
792
793
794
  	__u32 mtu;
  	int err;
  
  	if (ipv6_addr_equal(&t->parms.raddr, &ipv6h->saddr))
  		return -1;
6712abc16   William Tu   ip6_gre: add ip6 ...
795
796
  	if (!t->parms.collect_md &&
  	    prepare_ip6gre_xmit_ipv6(skb, dev, &fl6, &dsfield, &encap_limit))
898b29798   William Tu   ip6_gre: Refactor...
797
  		return -1;
e2d118a1c   Lorenzo Colitti   net: inet: Suppor...
798

b05229f44   Tom Herbert   gre6: Cleanup GRE...
799
800
801
802
803
  	if (gre_handle_offloads(skb, !!(t->parms.o_flags & TUNNEL_CSUM)))
  		return -1;
  
  	err = __gre6_xmit(skb, dev, dsfield, &fl6, encap_limit,
  			  &mtu, skb->protocol);
c12b395a4   xeb@mail.ru   gre: Support GRE ...
804
805
806
807
808
809
810
811
812
813
  	if (err != 0) {
  		if (err == -EMSGSIZE)
  			icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu);
  		return -1;
  	}
  
  	return 0;
  }
  
  /**
7ccbdff13   Sun Lianwen   ip6_gre: correct ...
814
   * ip6gre_tnl_addr_conflict - compare packet addresses to tunnel's own
c12b395a4   xeb@mail.ru   gre: Support GRE ...
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
   *   @t: the outgoing tunnel device
   *   @hdr: IPv6 header from the incoming packet
   *
   * Description:
   *   Avoid trivial tunneling loop by checking that tunnel exit-point
   *   doesn't match source of incoming packet.
   *
   * Return:
   *   1 if conflict,
   *   0 else
   **/
  
  static inline bool ip6gre_tnl_addr_conflict(const struct ip6_tnl *t,
  	const struct ipv6hdr *hdr)
  {
  	return ipv6_addr_equal(&t->parms.raddr, &hdr->saddr);
  }
  
  static int ip6gre_xmit_other(struct sk_buff *skb, struct net_device *dev)
  {
  	struct ip6_tnl *t = netdev_priv(dev);
  	int encap_limit = -1;
  	struct flowi6 fl6;
  	__u32 mtu;
  	int err;
  
  	if (!(t->parms.flags & IP6_TNL_F_IGN_ENCAP_LIMIT))
  		encap_limit = t->parms.encap_limit;
6712abc16   William Tu   ip6_gre: add ip6 ...
843
844
  	if (!t->parms.collect_md)
  		memcpy(&fl6, &t->fl.u.ip6, sizeof(fl6));
c12b395a4   xeb@mail.ru   gre: Support GRE ...
845

b05229f44   Tom Herbert   gre6: Cleanup GRE...
846
847
848
849
850
  	err = gre_handle_offloads(skb, !!(t->parms.o_flags & TUNNEL_CSUM));
  	if (err)
  		return err;
  
  	err = __gre6_xmit(skb, dev, 0, &fl6, encap_limit, &mtu, skb->protocol);
c12b395a4   xeb@mail.ru   gre: Support GRE ...
851
852
853
854
855
856
857
858
859
860
  
  	return err;
  }
  
  static netdev_tx_t ip6gre_tunnel_xmit(struct sk_buff *skb,
  	struct net_device *dev)
  {
  	struct ip6_tnl *t = netdev_priv(dev);
  	struct net_device_stats *stats = &t->dev->stats;
  	int ret;
cb9f1b783   Willem de Bruijn   ip: validate head...
861
862
  	if (!pskb_inet_may_pull(skb))
  		goto tx_err;
d50051407   Steffen Klassert   ipv6: Allow sendi...
863
  	if (!ip6_tnl_xmit_ctl(t, &t->parms.laddr, &t->parms.raddr))
41ab3e31b   Tommi Rantala   ipv6/ip6_gre: fix...
864
  		goto tx_err;
c12b395a4   xeb@mail.ru   gre: Support GRE ...
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
  
  	switch (skb->protocol) {
  	case htons(ETH_P_IP):
  		ret = ip6gre_xmit_ipv4(skb, dev);
  		break;
  	case htons(ETH_P_IPV6):
  		ret = ip6gre_xmit_ipv6(skb, dev);
  		break;
  	default:
  		ret = ip6gre_xmit_other(skb, dev);
  		break;
  	}
  
  	if (ret < 0)
  		goto tx_err;
  
  	return NETDEV_TX_OK;
  
  tx_err:
e5f7e211b   Davide Caratti   ip6gre: avoid tx_...
884
885
  	if (!t->parms.collect_md || !IS_ERR(skb_tunnel_info_txcheck(skb)))
  		stats->tx_errors++;
c12b395a4   xeb@mail.ru   gre: Support GRE ...
886
887
888
889
  	stats->tx_dropped++;
  	kfree_skb(skb);
  	return NETDEV_TX_OK;
  }
5a963eb61   William Tu   ip6_gre: Add ERSP...
890
891
892
  static netdev_tx_t ip6erspan_tunnel_xmit(struct sk_buff *skb,
  					 struct net_device *dev)
  {
e5f7e211b   Davide Caratti   ip6gre: avoid tx_...
893
  	struct ip_tunnel_info *tun_info = NULL;
5a963eb61   William Tu   ip6_gre: Add ERSP...
894
895
896
897
898
899
900
901
  	struct ip6_tnl *t = netdev_priv(dev);
  	struct dst_entry *dst = skb_dst(skb);
  	struct net_device_stats *stats;
  	bool truncate = false;
  	int encap_limit = -1;
  	__u8 dsfield = false;
  	struct flowi6 fl6;
  	int err = -EINVAL;
20704bd16   Xin Long   erspan: build the...
902
  	__be16 proto;
5a963eb61   William Tu   ip6_gre: Add ERSP...
903
  	__u32 mtu;
1baf5ebf8   William Tu   erspan: auto dete...
904
  	int nhoff;
d5db21a3e   William Tu   erspan: auto dete...
905
  	int thoff;
5a963eb61   William Tu   ip6_gre: Add ERSP...
906

cb9f1b783   Willem de Bruijn   ip: validate head...
907
908
  	if (!pskb_inet_may_pull(skb))
  		goto tx_err;
5a963eb61   William Tu   ip6_gre: Add ERSP...
909
910
911
912
913
  	if (!ip6_tnl_xmit_ctl(t, &t->parms.laddr, &t->parms.raddr))
  		goto tx_err;
  
  	if (gre_handle_offloads(skb, false))
  		goto tx_err;
5a963eb61   William Tu   ip6_gre: Add ERSP...
914
915
916
917
  	if (skb->len > dev->mtu + dev->hard_header_len) {
  		pskb_trim(skb, dev->mtu + dev->hard_header_len);
  		truncate = true;
  	}
1baf5ebf8   William Tu   erspan: auto dete...
918
919
920
921
  	nhoff = skb_network_header(skb) - skb_mac_header(skb);
  	if (skb->protocol == htons(ETH_P_IP) &&
  	    (ntohs(ip_hdr(skb)->tot_len) > skb->len - nhoff))
  		truncate = true;
d5db21a3e   William Tu   erspan: auto dete...
922
923
924
925
  	thoff = skb_transport_header(skb) - skb_mac_header(skb);
  	if (skb->protocol == htons(ETH_P_IPV6) &&
  	    (ntohs(ipv6_hdr(skb)->payload_len) > skb->len - thoff))
  		truncate = true;
5691484df   Petr Machata   net: ip6_gre: Fix...
926
  	if (skb_cow_head(skb, dev->needed_headroom ?: t->hlen))
e41c7c68e   William Tu   ip6erspan: make s...
927
  		goto tx_err;
5a963eb61   William Tu   ip6_gre: Add ERSP...
928
  	t->parms.o_flags &= ~TUNNEL_KEY;
5a963eb61   William Tu   ip6_gre: Add ERSP...
929
  	IPCB(skb)->flags = 0;
ef7baf5e0   William Tu   ip6_gre: add ip6 ...
930
931
932
933
934
  
  	/* For collect_md mode, derive fl6 from the tunnel key,
  	 * for native mode, call prepare_ip6gre_xmit_{ipv4,ipv6}.
  	 */
  	if (t->parms.collect_md) {
ef7baf5e0   William Tu   ip6_gre: add ip6 ...
935
936
  		const struct ip_tunnel_key *key;
  		struct erspan_metadata *md;
c69de58ba   William Tu   net: erspan: use ...
937
  		__be32 tun_id;
ef7baf5e0   William Tu   ip6_gre: add ip6 ...
938

e5f7e211b   Davide Caratti   ip6gre: avoid tx_...
939
940
941
  		tun_info = skb_tunnel_info_txcheck(skb);
  		if (IS_ERR(tun_info) ||
  		    unlikely(ip_tunnel_info_af(tun_info) != AF_INET6))
28e486037   Xin Long   ip6_gre: fix a ds...
942
  			goto tx_err;
ef7baf5e0   William Tu   ip6_gre: add ip6 ...
943
944
945
946
947
948
949
950
951
  
  		key = &tun_info->key;
  		memset(&fl6, 0, sizeof(fl6));
  		fl6.flowi6_proto = IPPROTO_GRE;
  		fl6.daddr = key->u.ipv6.dst;
  		fl6.flowlabel = key->label;
  		fl6.flowi6_uid = sock_net_uid(dev_net(dev), NULL);
  
  		dsfield = key->tos;
256c87c17   Pieter Jansen van Vuuren   net: check tunnel...
952
953
  		if (!(tun_info->key.tun_flags & TUNNEL_ERSPAN_OPT))
  			goto tx_err;
2eb8d6d29   Xin Long   erspan: fix the t...
954
  		if (tun_info->options_len < sizeof(*md))
ef7baf5e0   William Tu   ip6_gre: add ip6 ...
955
  			goto tx_err;
2eb8d6d29   Xin Long   erspan: fix the t...
956
  		md = ip_tunnel_info_opts(tun_info);
ef7baf5e0   William Tu   ip6_gre: add ip6 ...
957

c69de58ba   William Tu   net: erspan: use ...
958
  		tun_id = tunnel_id_to_key32(key->tun_id);
94d7d8f29   William Tu   ip6_gre: add ersp...
959
960
  		if (md->version == 1) {
  			erspan_build_header(skb,
c69de58ba   William Tu   net: erspan: use ...
961
  					    ntohl(tun_id),
94d7d8f29   William Tu   ip6_gre: add ersp...
962
963
964
  					    ntohl(md->u.index), truncate,
  					    false);
  		} else if (md->version == 2) {
94d7d8f29   William Tu   ip6_gre: add ersp...
965
  			erspan_build_header_v2(skb,
c69de58ba   William Tu   net: erspan: use ...
966
967
968
969
  					       ntohl(tun_id),
  					       md->u.md2.dir,
  					       get_hwid(&md->u.md2),
  					       truncate, false);
d6aa71197   William Tu   ip6erspan: improv...
970
971
  		} else {
  			goto tx_err;
94d7d8f29   William Tu   ip6_gre: add ersp...
972
  		}
ef7baf5e0   William Tu   ip6_gre: add ip6 ...
973
974
975
976
977
978
979
980
  	} else {
  		switch (skb->protocol) {
  		case htons(ETH_P_IP):
  			memset(&(IPCB(skb)->opt), 0, sizeof(IPCB(skb)->opt));
  			prepare_ip6gre_xmit_ipv4(skb, dev, &fl6,
  						 &dsfield, &encap_limit);
  			break;
  		case htons(ETH_P_IPV6):
cb9f1b783   Willem de Bruijn   ip: validate head...
981
  			if (ipv6_addr_equal(&t->parms.raddr, &ipv6_hdr(skb)->saddr))
ef7baf5e0   William Tu   ip6_gre: add ip6 ...
982
983
984
985
986
987
988
989
990
  				goto tx_err;
  			if (prepare_ip6gre_xmit_ipv6(skb, dev, &fl6,
  						     &dsfield, &encap_limit))
  				goto tx_err;
  			break;
  		default:
  			memcpy(&fl6, &t->fl.u.ip6, sizeof(fl6));
  			break;
  		}
94d7d8f29   William Tu   ip6_gre: add ersp...
991
  		if (t->parms.erspan_ver == 1)
c69de58ba   William Tu   net: erspan: use ...
992
  			erspan_build_header(skb, ntohl(t->parms.o_key),
94d7d8f29   William Tu   ip6_gre: add ersp...
993
994
  					    t->parms.index,
  					    truncate, false);
02f99df18   William Tu   erspan: fix inval...
995
  		else if (t->parms.erspan_ver == 2)
c69de58ba   William Tu   net: erspan: use ...
996
  			erspan_build_header_v2(skb, ntohl(t->parms.o_key),
94d7d8f29   William Tu   ip6_gre: add ersp...
997
998
999
  					       t->parms.dir,
  					       t->parms.hwid,
  					       truncate, false);
02f99df18   William Tu   erspan: fix inval...
1000
1001
  		else
  			goto tx_err;
ef7baf5e0   William Tu   ip6_gre: add ip6 ...
1002
1003
  		fl6.daddr = t->parms.raddr;
  	}
5a963eb61   William Tu   ip6_gre: Add ERSP...
1004
1005
  
  	/* Push GRE header. */
20704bd16   Xin Long   erspan: build the...
1006
1007
1008
  	proto = (t->parms.erspan_ver == 1) ? htons(ETH_P_ERSPAN)
  					   : htons(ETH_P_ERSPAN2);
  	gre_build_header(skb, 8, TUNNEL_SEQ, proto, 0, htonl(t->o_seqno++));
5a963eb61   William Tu   ip6_gre: Add ERSP...
1009
1010
  
  	/* TooBig packet may have updated dst->dev's mtu */
ef7baf5e0   William Tu   ip6_gre: add ip6 ...
1011
  	if (!t->parms.collect_md && dst && dst_mtu(dst) > dst->dev->mtu)
675d76ad0   Hangbin Liu   ip6_gre: do not c...
1012
  		dst->ops->update_pmtu(dst, NULL, skb, dst->dev->mtu, false);
5a963eb61   William Tu   ip6_gre: Add ERSP...
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
  
  	err = ip6_tnl_xmit(skb, dev, dsfield, &fl6, encap_limit, &mtu,
  			   NEXTHDR_GRE);
  	if (err != 0) {
  		/* XXX: send ICMP error even if DF is not set. */
  		if (err == -EMSGSIZE) {
  			if (skb->protocol == htons(ETH_P_IP))
  				icmp_send(skb, ICMP_DEST_UNREACH,
  					  ICMP_FRAG_NEEDED, htonl(mtu));
  			else
  				icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu);
  		}
  
  		goto tx_err;
  	}
  	return NETDEV_TX_OK;
  
  tx_err:
  	stats = &t->dev->stats;
e5f7e211b   Davide Caratti   ip6gre: avoid tx_...
1032
1033
  	if (!IS_ERR(tun_info))
  		stats->tx_errors++;
5a963eb61   William Tu   ip6_gre: Add ERSP...
1034
1035
1036
1037
  	stats->tx_dropped++;
  	kfree_skb(skb);
  	return NETDEV_TX_OK;
  }
a483373ea   Petr Machata   net: ip6_gre: Spl...
1038
  static void ip6gre_tnl_link_config_common(struct ip6_tnl *t)
c12b395a4   xeb@mail.ru   gre: Support GRE ...
1039
1040
1041
1042
  {
  	struct net_device *dev = t->dev;
  	struct __ip6_tnl_parm *p = &t->parms;
  	struct flowi6 *fl6 = &t->fl.u.ip6;
c12b395a4   xeb@mail.ru   gre: Support GRE ...
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
  
  	if (dev->type != ARPHRD_ETHER) {
  		memcpy(dev->dev_addr, &p->laddr, sizeof(struct in6_addr));
  		memcpy(dev->broadcast, &p->raddr, sizeof(struct in6_addr));
  	}
  
  	/* Set up flowi template */
  	fl6->saddr = p->laddr;
  	fl6->daddr = p->raddr;
  	fl6->flowi6_oif = p->link;
  	fl6->flowlabel = 0;
252f3f5a1   Haishuang Yan   ip6_gre: Set flow...
1054
  	fl6->flowi6_proto = IPPROTO_GRE;
c12b395a4   xeb@mail.ru   gre: Support GRE ...
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
  
  	if (!(p->flags&IP6_TNL_F_USE_ORIG_TCLASS))
  		fl6->flowlabel |= IPV6_TCLASS_MASK & p->flowinfo;
  	if (!(p->flags&IP6_TNL_F_USE_ORIG_FLOWLABEL))
  		fl6->flowlabel |= IPV6_FLOWLABEL_MASK & p->flowinfo;
  
  	p->flags &= ~(IP6_TNL_F_CAP_XMIT|IP6_TNL_F_CAP_RCV|IP6_TNL_F_CAP_PER_PACKET);
  	p->flags |= ip6_tnl_get_cap(t, &p->laddr, &p->raddr);
  
  	if (p->flags&IP6_TNL_F_CAP_XMIT &&
  			p->flags&IP6_TNL_F_CAP_RCV && dev->type != ARPHRD_ETHER)
  		dev->flags |= IFF_POINTOPOINT;
  	else
  		dev->flags &= ~IFF_POINTOPOINT;
a483373ea   Petr Machata   net: ip6_gre: Spl...
1069
  }
c12b395a4   xeb@mail.ru   gre: Support GRE ...
1070

a483373ea   Petr Machata   net: ip6_gre: Spl...
1071
1072
1073
1074
1075
  static void ip6gre_tnl_link_config_route(struct ip6_tnl *t, int set_mtu,
  					 int t_hlen)
  {
  	const struct __ip6_tnl_parm *p = &t->parms;
  	struct net_device *dev = t->dev;
c12b395a4   xeb@mail.ru   gre: Support GRE ...
1076
1077
1078
1079
  
  	if (p->flags & IP6_TNL_F_CAP_XMIT) {
  		int strict = (ipv6_addr_type(&p->raddr) &
  			      (IPV6_ADDR_MULTICAST|IPV6_ADDR_LINKLOCAL));
22f08069e   Nicolas Dichtel   ip6gre: add x-net...
1080
  		struct rt6_info *rt = rt6_lookup(t->net,
c12b395a4   xeb@mail.ru   gre: Support GRE ...
1081
  						 &p->raddr, &p->laddr,
b75cc8f90   David Ahern   net/ipv6: Pass sk...
1082
  						 p->link, NULL, strict);
c12b395a4   xeb@mail.ru   gre: Support GRE ...
1083

63159f29b   Ian Morris   ipv6: coding styl...
1084
  		if (!rt)
c12b395a4   xeb@mail.ru   gre: Support GRE ...
1085
1086
1087
  			return;
  
  		if (rt->dst.dev) {
832ba5964   Antoine Tenart   net: ip6_gre: set...
1088
1089
1090
1091
1092
1093
1094
  			unsigned short dst_len = rt->dst.dev->hard_header_len +
  						 t_hlen;
  
  			if (t->dev->header_ops)
  				dev->hard_header_len = dst_len;
  			else
  				dev->needed_headroom = dst_len;
c12b395a4   xeb@mail.ru   gre: Support GRE ...
1095
1096
  
  			if (set_mtu) {
db2ec95d1   Tom Herbert   ip6_gre: Fix MTU ...
1097
  				dev->mtu = rt->dst.dev->mtu - t_hlen;
c12b395a4   xeb@mail.ru   gre: Support GRE ...
1098
1099
  				if (!(t->parms.flags & IP6_TNL_F_IGN_ENCAP_LIMIT))
  					dev->mtu -= 8;
a9e242ca4   Alexander Duyck   ip6gretap: Fix MT...
1100
1101
  				if (dev->type == ARPHRD_ETHER)
  					dev->mtu -= ETH_HLEN;
c12b395a4   xeb@mail.ru   gre: Support GRE ...
1102
1103
1104
1105
1106
  
  				if (dev->mtu < IPV6_MIN_MTU)
  					dev->mtu = IPV6_MIN_MTU;
  			}
  		}
94e187c01   Amerigo Wang   ipv6: introduce i...
1107
  		ip6_rt_put(rt);
c12b395a4   xeb@mail.ru   gre: Support GRE ...
1108
  	}
c12b395a4   xeb@mail.ru   gre: Support GRE ...
1109
  }
a483373ea   Petr Machata   net: ip6_gre: Spl...
1110
1111
1112
1113
1114
1115
1116
1117
  static int ip6gre_calc_hlen(struct ip6_tnl *tunnel)
  {
  	int t_hlen;
  
  	tunnel->tun_hlen = gre_calc_hlen(tunnel->parms.o_flags);
  	tunnel->hlen = tunnel->tun_hlen + tunnel->encap_hlen;
  
  	t_hlen = tunnel->hlen + sizeof(struct ipv6hdr);
832ba5964   Antoine Tenart   net: ip6_gre: set...
1118
1119
1120
1121
1122
  
  	if (tunnel->dev->header_ops)
  		tunnel->dev->hard_header_len = LL_MAX_HEADER + t_hlen;
  	else
  		tunnel->dev->needed_headroom = LL_MAX_HEADER + t_hlen;
a483373ea   Petr Machata   net: ip6_gre: Spl...
1123
1124
1125
1126
1127
1128
1129
1130
  	return t_hlen;
  }
  
  static void ip6gre_tnl_link_config(struct ip6_tnl *t, int set_mtu)
  {
  	ip6gre_tnl_link_config_common(t);
  	ip6gre_tnl_link_config_route(t, set_mtu, ip6gre_calc_hlen(t));
  }
a6465350e   Petr Machata   net: ip6_gre: Spl...
1131
1132
  static void ip6gre_tnl_copy_tnl_parm(struct ip6_tnl *t,
  				     const struct __ip6_tnl_parm *p)
c12b395a4   xeb@mail.ru   gre: Support GRE ...
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
  {
  	t->parms.laddr = p->laddr;
  	t->parms.raddr = p->raddr;
  	t->parms.flags = p->flags;
  	t->parms.hop_limit = p->hop_limit;
  	t->parms.encap_limit = p->encap_limit;
  	t->parms.flowinfo = p->flowinfo;
  	t->parms.link = p->link;
  	t->parms.proto = p->proto;
  	t->parms.i_key = p->i_key;
  	t->parms.o_key = p->o_key;
  	t->parms.i_flags = p->i_flags;
  	t->parms.o_flags = p->o_flags;
0a473b82c   Craig Gallek   ip6_tunnel: Allow...
1146
  	t->parms.fwmark = p->fwmark;
80b3671e9   Hangbin Liu   ip6_gre: update v...
1147
1148
1149
1150
  	t->parms.erspan_ver = p->erspan_ver;
  	t->parms.index = p->index;
  	t->parms.dir = p->dir;
  	t->parms.hwid = p->hwid;
607f725f6   Paolo Abeni   net: replace dst_...
1151
  	dst_cache_reset(&t->dst_cache);
a6465350e   Petr Machata   net: ip6_gre: Spl...
1152
1153
1154
1155
1156
1157
  }
  
  static int ip6gre_tnl_change(struct ip6_tnl *t, const struct __ip6_tnl_parm *p,
  			     int set_mtu)
  {
  	ip6gre_tnl_copy_tnl_parm(t, p);
c12b395a4   xeb@mail.ru   gre: Support GRE ...
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
  	ip6gre_tnl_link_config(t, set_mtu);
  	return 0;
  }
  
  static void ip6gre_tnl_parm_from_user(struct __ip6_tnl_parm *p,
  	const struct ip6_tnl_parm2 *u)
  {
  	p->laddr = u->laddr;
  	p->raddr = u->raddr;
  	p->flags = u->flags;
  	p->hop_limit = u->hop_limit;
  	p->encap_limit = u->encap_limit;
  	p->flowinfo = u->flowinfo;
  	p->link = u->link;
  	p->i_key = u->i_key;
  	p->o_key = u->o_key;
f41fe3c2a   Tom Herbert   gre6: Fix flag tr...
1174
1175
  	p->i_flags = gre_flags_to_tnl_flags(u->i_flags);
  	p->o_flags = gre_flags_to_tnl_flags(u->o_flags);
c12b395a4   xeb@mail.ru   gre: Support GRE ...
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
  	memcpy(p->name, u->name, sizeof(u->name));
  }
  
  static void ip6gre_tnl_parm_to_user(struct ip6_tnl_parm2 *u,
  	const struct __ip6_tnl_parm *p)
  {
  	u->proto = IPPROTO_GRE;
  	u->laddr = p->laddr;
  	u->raddr = p->raddr;
  	u->flags = p->flags;
  	u->hop_limit = p->hop_limit;
  	u->encap_limit = p->encap_limit;
  	u->flowinfo = p->flowinfo;
  	u->link = p->link;
  	u->i_key = p->i_key;
  	u->o_key = p->o_key;
f41fe3c2a   Tom Herbert   gre6: Fix flag tr...
1192
1193
  	u->i_flags = gre_tnl_flags_to_gre_flags(p->i_flags);
  	u->o_flags = gre_tnl_flags_to_gre_flags(p->o_flags);
c12b395a4   xeb@mail.ru   gre: Support GRE ...
1194
1195
1196
1197
1198
1199
1200
1201
1202
  	memcpy(u->name, p->name, sizeof(u->name));
  }
  
  static int ip6gre_tunnel_ioctl(struct net_device *dev,
  	struct ifreq *ifr, int cmd)
  {
  	int err = 0;
  	struct ip6_tnl_parm2 p;
  	struct __ip6_tnl_parm p1;
22f08069e   Nicolas Dichtel   ip6gre: add x-net...
1203
1204
  	struct ip6_tnl *t = netdev_priv(dev);
  	struct net *net = t->net;
c12b395a4   xeb@mail.ru   gre: Support GRE ...
1205
  	struct ip6gre_net *ign = net_generic(net, ip6gre_net_id);
308edfdf1   Tom Herbert   gre6: Cleanup GRE...
1206
  	memset(&p1, 0, sizeof(p1));
c12b395a4   xeb@mail.ru   gre: Support GRE ...
1207
1208
  	switch (cmd) {
  	case SIOCGETTUNNEL:
c12b395a4   xeb@mail.ru   gre: Support GRE ...
1209
1210
1211
1212
1213
1214
1215
  		if (dev == ign->fb_tunnel_dev) {
  			if (copy_from_user(&p, ifr->ifr_ifru.ifru_data, sizeof(p))) {
  				err = -EFAULT;
  				break;
  			}
  			ip6gre_tnl_parm_from_user(&p1, &p);
  			t = ip6gre_tunnel_locate(net, &p1, 0);
63159f29b   Ian Morris   ipv6: coding styl...
1216
  			if (!t)
22f08069e   Nicolas Dichtel   ip6gre: add x-net...
1217
  				t = netdev_priv(dev);
c12b395a4   xeb@mail.ru   gre: Support GRE ...
1218
  		}
5dbd50684   Amerigo Wang   ipv6,gre: do not ...
1219
  		memset(&p, 0, sizeof(p));
c12b395a4   xeb@mail.ru   gre: Support GRE ...
1220
1221
1222
1223
1224
1225
1226
1227
  		ip6gre_tnl_parm_to_user(&p, &t->parms);
  		if (copy_to_user(ifr->ifr_ifru.ifru_data, &p, sizeof(p)))
  			err = -EFAULT;
  		break;
  
  	case SIOCADDTUNNEL:
  	case SIOCCHGTUNNEL:
  		err = -EPERM;
af31f412c   Eric W. Biederman   net: Allow userns...
1228
  		if (!ns_capable(net->user_ns, CAP_NET_ADMIN))
c12b395a4   xeb@mail.ru   gre: Support GRE ...
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
  			goto done;
  
  		err = -EFAULT;
  		if (copy_from_user(&p, ifr->ifr_ifru.ifru_data, sizeof(p)))
  			goto done;
  
  		err = -EINVAL;
  		if ((p.i_flags|p.o_flags)&(GRE_VERSION|GRE_ROUTING))
  			goto done;
  
  		if (!(p.i_flags&GRE_KEY))
  			p.i_key = 0;
  		if (!(p.o_flags&GRE_KEY))
  			p.o_key = 0;
  
  		ip6gre_tnl_parm_from_user(&p1, &p);
  		t = ip6gre_tunnel_locate(net, &p1, cmd == SIOCADDTUNNEL);
  
  		if (dev != ign->fb_tunnel_dev && cmd == SIOCCHGTUNNEL) {
53b24b8f9   Ian Morris   ipv6: coding styl...
1248
  			if (t) {
c12b395a4   xeb@mail.ru   gre: Support GRE ...
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
  				if (t->dev != dev) {
  					err = -EEXIST;
  					break;
  				}
  			} else {
  				t = netdev_priv(dev);
  
  				ip6gre_tunnel_unlink(ign, t);
  				synchronize_net();
  				ip6gre_tnl_change(t, &p1, 1);
  				ip6gre_tunnel_link(ign, t);
  				netdev_state_change(dev);
  			}
  		}
  
  		if (t) {
  			err = 0;
5dbd50684   Amerigo Wang   ipv6,gre: do not ...
1266
  			memset(&p, 0, sizeof(p));
c12b395a4   xeb@mail.ru   gre: Support GRE ...
1267
1268
1269
1270
1271
1272
1273
1274
1275
  			ip6gre_tnl_parm_to_user(&p, &t->parms);
  			if (copy_to_user(ifr->ifr_ifru.ifru_data, &p, sizeof(p)))
  				err = -EFAULT;
  		} else
  			err = (cmd == SIOCADDTUNNEL ? -ENOBUFS : -ENOENT);
  		break;
  
  	case SIOCDELTUNNEL:
  		err = -EPERM;
af31f412c   Eric W. Biederman   net: Allow userns...
1276
  		if (!ns_capable(net->user_ns, CAP_NET_ADMIN))
c12b395a4   xeb@mail.ru   gre: Support GRE ...
1277
1278
1279
1280
1281
1282
1283
1284
1285
  			goto done;
  
  		if (dev == ign->fb_tunnel_dev) {
  			err = -EFAULT;
  			if (copy_from_user(&p, ifr->ifr_ifru.ifru_data, sizeof(p)))
  				goto done;
  			err = -ENOENT;
  			ip6gre_tnl_parm_from_user(&p1, &p);
  			t = ip6gre_tunnel_locate(net, &p1, 0);
63159f29b   Ian Morris   ipv6: coding styl...
1286
  			if (!t)
c12b395a4   xeb@mail.ru   gre: Support GRE ...
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
  				goto done;
  			err = -EPERM;
  			if (t == netdev_priv(ign->fb_tunnel_dev))
  				goto done;
  			dev = t->dev;
  		}
  		unregister_netdevice(dev);
  		err = 0;
  		break;
  
  	default:
  		err = -EINVAL;
  	}
  
  done:
  	return err;
  }
c12b395a4   xeb@mail.ru   gre: Support GRE ...
1304
  static int ip6gre_header(struct sk_buff *skb, struct net_device *dev,
76cc0d328   Xin Long   ip6_gre: skb_push...
1305
1306
  			 unsigned short type, const void *daddr,
  			 const void *saddr, unsigned int len)
c12b395a4   xeb@mail.ru   gre: Support GRE ...
1307
1308
  {
  	struct ip6_tnl *t = netdev_priv(dev);
76cc0d328   Xin Long   ip6_gre: skb_push...
1309
1310
  	struct ipv6hdr *ipv6h;
  	__be16 *p;
c12b395a4   xeb@mail.ru   gre: Support GRE ...
1311

76cc0d328   Xin Long   ip6_gre: skb_push...
1312
1313
1314
1315
  	ipv6h = skb_push(skb, t->hlen + sizeof(*ipv6h));
  	ip6_flow_hdr(ipv6h, 0, ip6_make_flowlabel(dev_net(dev), skb,
  						  t->fl.u.ip6.flowlabel,
  						  true, &t->fl.u.ip6));
c12b395a4   xeb@mail.ru   gre: Support GRE ...
1316
1317
1318
1319
  	ipv6h->hop_limit = t->parms.hop_limit;
  	ipv6h->nexthdr = NEXTHDR_GRE;
  	ipv6h->saddr = t->parms.laddr;
  	ipv6h->daddr = t->parms.raddr;
76cc0d328   Xin Long   ip6_gre: skb_push...
1320
1321
1322
  	p = (__be16 *)(ipv6h + 1);
  	p[0] = t->parms.o_flags;
  	p[1] = htons(type);
c12b395a4   xeb@mail.ru   gre: Support GRE ...
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
  
  	/*
  	 *	Set the source hardware address.
  	 */
  
  	if (saddr)
  		memcpy(&ipv6h->saddr, saddr, sizeof(struct in6_addr));
  	if (daddr)
  		memcpy(&ipv6h->daddr, daddr, sizeof(struct in6_addr));
  	if (!ipv6_addr_any(&ipv6h->daddr))
  		return t->hlen;
  
  	return -t->hlen;
  }
c12b395a4   xeb@mail.ru   gre: Support GRE ...
1337
1338
  static const struct header_ops ip6gre_header_ops = {
  	.create	= ip6gre_header,
c12b395a4   xeb@mail.ru   gre: Support GRE ...
1339
1340
1341
1342
1343
1344
1345
  };
  
  static const struct net_device_ops ip6gre_netdev_ops = {
  	.ndo_init		= ip6gre_tunnel_init,
  	.ndo_uninit		= ip6gre_tunnel_uninit,
  	.ndo_start_xmit		= ip6gre_tunnel_xmit,
  	.ndo_do_ioctl		= ip6gre_tunnel_ioctl,
b05229f44   Tom Herbert   gre6: Cleanup GRE...
1346
  	.ndo_change_mtu		= ip6_tnl_change_mtu,
f61dd388a   Pravin B Shelar   Tunneling: use IP...
1347
  	.ndo_get_stats64	= ip_tunnel_get_stats64,
ecf2c06a8   Nicolas Dichtel   ip6tnl,gre6,vti6:...
1348
  	.ndo_get_iflink		= ip6_tnl_get_iflink,
c12b395a4   xeb@mail.ru   gre: Support GRE ...
1349
1350
1351
1352
  };
  
  static void ip6gre_dev_free(struct net_device *dev)
  {
cdf3464e6   Martin KaFai Lau   ipv6: Fix dst_ent...
1353
  	struct ip6_tnl *t = netdev_priv(dev);
0c1dd2a16   Eran Ben Elisha   net: ipv6/gre: Ad...
1354
  	gro_cells_destroy(&t->gro_cells);
607f725f6   Paolo Abeni   net: replace dst_...
1355
  	dst_cache_destroy(&t->dst_cache);
c12b395a4   xeb@mail.ru   gre: Support GRE ...
1356
  	free_percpu(dev->tstats);
c12b395a4   xeb@mail.ru   gre: Support GRE ...
1357
1358
1359
1360
  }
  
  static void ip6gre_tunnel_setup(struct net_device *dev)
  {
c12b395a4   xeb@mail.ru   gre: Support GRE ...
1361
  	dev->netdev_ops = &ip6gre_netdev_ops;
cf124db56   David S. Miller   net: Fix inconsis...
1362
1363
  	dev->needs_free_netdev = true;
  	dev->priv_destructor = ip6gre_dev_free;
c12b395a4   xeb@mail.ru   gre: Support GRE ...
1364
1365
  
  	dev->type = ARPHRD_IP6GRE;
b05229f44   Tom Herbert   gre6: Cleanup GRE...
1366

c12b395a4   xeb@mail.ru   gre: Support GRE ...
1367
  	dev->flags |= IFF_NOARP;
c12b395a4   xeb@mail.ru   gre: Support GRE ...
1368
  	dev->addr_len = sizeof(struct in6_addr);
028758788   Eric Dumazet   net: better IFF_X...
1369
  	netif_keep_dst(dev);
45ce0fd19   Felix Jia   net/ipv6: support...
1370
1371
1372
  	/* This perm addr will be used as interface identifier by IPv6 */
  	dev->addr_assign_type = NET_ADDR_RANDOM;
  	eth_random_addr(dev->perm_addr);
c12b395a4   xeb@mail.ru   gre: Support GRE ...
1373
  }
e5a9336ad   Alexey Kodanev   ip6_gre: fix devi...
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
  #define GRE6_FEATURES (NETIF_F_SG |		\
  		       NETIF_F_FRAGLIST |	\
  		       NETIF_F_HIGHDMA |	\
  		       NETIF_F_HW_CSUM)
  
  static void ip6gre_tnl_init_features(struct net_device *dev)
  {
  	struct ip6_tnl *nt = netdev_priv(dev);
  
  	dev->features		|= GRE6_FEATURES;
  	dev->hw_features	|= GRE6_FEATURES;
  
  	if (!(nt->parms.o_flags & TUNNEL_SEQ)) {
  		/* TCP offload with GRE SEQ is not supported, nor
  		 * can we support 2 levels of outer headers requiring
  		 * an update.
  		 */
  		if (!(nt->parms.o_flags & TUNNEL_CSUM) ||
  		    nt->encap.type == TUNNEL_ENCAP_NONE) {
  			dev->features    |= NETIF_F_GSO_SOFTWARE;
  			dev->hw_features |= NETIF_F_GSO_SOFTWARE;
  		}
  
  		/* Can use a lockless transmit, unless we generate
  		 * output sequences
  		 */
  		dev->features |= NETIF_F_LLTX;
  	}
  }
a3c119d39   Martin KaFai Lau   ipv6: Refactor co...
1403
  static int ip6gre_tunnel_init_common(struct net_device *dev)
c12b395a4   xeb@mail.ru   gre: Support GRE ...
1404
1405
  {
  	struct ip6_tnl *tunnel;
cdf3464e6   Martin KaFai Lau   ipv6: Fix dst_ent...
1406
  	int ret;
b05229f44   Tom Herbert   gre6: Cleanup GRE...
1407
  	int t_hlen;
c12b395a4   xeb@mail.ru   gre: Support GRE ...
1408
1409
1410
1411
  
  	tunnel = netdev_priv(dev);
  
  	tunnel->dev = dev;
0bd876282   Nicolas Dichtel   ip6tnl: add x-net...
1412
  	tunnel->net = dev_net(dev);
c12b395a4   xeb@mail.ru   gre: Support GRE ...
1413
  	strcpy(tunnel->parms.name, dev->name);
a3c119d39   Martin KaFai Lau   ipv6: Refactor co...
1414
1415
1416
  	dev->tstats = netdev_alloc_pcpu_stats(struct pcpu_sw_netstats);
  	if (!dev->tstats)
  		return -ENOMEM;
607f725f6   Paolo Abeni   net: replace dst_...
1417
  	ret = dst_cache_init(&tunnel->dst_cache, GFP_KERNEL);
0c1dd2a16   Eran Ben Elisha   net: ipv6/gre: Ad...
1418
1419
1420
1421
1422
1423
  	if (ret)
  		goto cleanup_alloc_pcpu_stats;
  
  	ret = gro_cells_init(&tunnel->gro_cells, dev);
  	if (ret)
  		goto cleanup_dst_cache_init;
cdf3464e6   Martin KaFai Lau   ipv6: Fix dst_ent...
1424

a483373ea   Petr Machata   net: ip6_gre: Spl...
1425
  	t_hlen = ip6gre_calc_hlen(tunnel);
db2ec95d1   Tom Herbert   ip6_gre: Fix MTU ...
1426
  	dev->mtu = ETH_DATA_LEN - t_hlen;
1b227e536   Haishuang Yan   ip6_gre: Fix MTU ...
1427
1428
  	if (dev->type == ARPHRD_ETHER)
  		dev->mtu -= ETH_HLEN;
b05229f44   Tom Herbert   gre6: Cleanup GRE...
1429
1430
  	if (!(tunnel->parms.flags & IP6_TNL_F_IGN_ENCAP_LIMIT))
  		dev->mtu -= 8;
6712abc16   William Tu   ip6_gre: add ip6 ...
1431
  	if (tunnel->parms.collect_md) {
6712abc16   William Tu   ip6_gre: add ip6 ...
1432
1433
  		netif_keep_dst(dev);
  	}
e5a9336ad   Alexey Kodanev   ip6_gre: fix devi...
1434
  	ip6gre_tnl_init_features(dev);
6712abc16   William Tu   ip6_gre: add ip6 ...
1435

a3c119d39   Martin KaFai Lau   ipv6: Refactor co...
1436
  	return 0;
0c1dd2a16   Eran Ben Elisha   net: ipv6/gre: Ad...
1437
1438
1439
1440
1441
1442
1443
  
  cleanup_dst_cache_init:
  	dst_cache_destroy(&tunnel->dst_cache);
  cleanup_alloc_pcpu_stats:
  	free_percpu(dev->tstats);
  	dev->tstats = NULL;
  	return ret;
a3c119d39   Martin KaFai Lau   ipv6: Refactor co...
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
  }
  
  static int ip6gre_tunnel_init(struct net_device *dev)
  {
  	struct ip6_tnl *tunnel;
  	int ret;
  
  	ret = ip6gre_tunnel_init_common(dev);
  	if (ret)
  		return ret;
  
  	tunnel = netdev_priv(dev);
6712abc16   William Tu   ip6_gre: add ip6 ...
1456
1457
  	if (tunnel->parms.collect_md)
  		return 0;
c12b395a4   xeb@mail.ru   gre: Support GRE ...
1458
1459
1460
1461
1462
  	memcpy(dev->dev_addr, &tunnel->parms.laddr, sizeof(struct in6_addr));
  	memcpy(dev->broadcast, &tunnel->parms.raddr, sizeof(struct in6_addr));
  
  	if (ipv6_addr_any(&tunnel->parms.raddr))
  		dev->header_ops = &ip6gre_header_ops;
c12b395a4   xeb@mail.ru   gre: Support GRE ...
1463
1464
1465
1466
1467
1468
1469
1470
  	return 0;
  }
  
  static void ip6gre_fb_tunnel_init(struct net_device *dev)
  {
  	struct ip6_tnl *tunnel = netdev_priv(dev);
  
  	tunnel->dev = dev;
0bd876282   Nicolas Dichtel   ip6tnl: add x-net...
1471
  	tunnel->net = dev_net(dev);
c12b395a4   xeb@mail.ru   gre: Support GRE ...
1472
1473
1474
1475
1476
1477
  	strcpy(tunnel->parms.name, dev->name);
  
  	tunnel->hlen		= sizeof(struct ipv6hdr) + 4;
  
  	dev_hold(dev);
  }
c12b395a4   xeb@mail.ru   gre: Support GRE ...
1478
  static struct inet6_protocol ip6gre_protocol __read_mostly = {
308edfdf1   Tom Herbert   gre6: Cleanup GRE...
1479
  	.handler     = gre_rcv,
c12b395a4   xeb@mail.ru   gre: Support GRE ...
1480
1481
1482
  	.err_handler = ip6gre_err,
  	.flags       = INET6_PROTO_NOPOLICY|INET6_PROTO_FINAL,
  };
22f08069e   Nicolas Dichtel   ip6gre: add x-net...
1483
  static void ip6gre_destroy_tunnels(struct net *net, struct list_head *head)
c12b395a4   xeb@mail.ru   gre: Support GRE ...
1484
  {
22f08069e   Nicolas Dichtel   ip6gre: add x-net...
1485
1486
  	struct ip6gre_net *ign = net_generic(net, ip6gre_net_id);
  	struct net_device *dev, *aux;
c12b395a4   xeb@mail.ru   gre: Support GRE ...
1487
  	int prio;
22f08069e   Nicolas Dichtel   ip6gre: add x-net...
1488
1489
  	for_each_netdev_safe(net, dev, aux)
  		if (dev->rtnl_link_ops == &ip6gre_link_ops ||
5a963eb61   William Tu   ip6_gre: Add ERSP...
1490
1491
  		    dev->rtnl_link_ops == &ip6gre_tap_ops ||
  		    dev->rtnl_link_ops == &ip6erspan_tap_ops)
22f08069e   Nicolas Dichtel   ip6gre: add x-net...
1492
  			unregister_netdevice_queue(dev, head);
c12b395a4   xeb@mail.ru   gre: Support GRE ...
1493
1494
  	for (prio = 0; prio < 4; prio++) {
  		int h;
e87a8f24c   Jiri Kosina   net: resolve symb...
1495
  		for (h = 0; h < IP6_GRE_HASH_SIZE; h++) {
c12b395a4   xeb@mail.ru   gre: Support GRE ...
1496
1497
1498
  			struct ip6_tnl *t;
  
  			t = rtnl_dereference(ign->tunnels[prio][h]);
53b24b8f9   Ian Morris   ipv6: coding styl...
1499
  			while (t) {
22f08069e   Nicolas Dichtel   ip6gre: add x-net...
1500
1501
1502
1503
1504
1505
  				/* If dev is in the same netns, it has already
  				 * been added to the list by the previous loop.
  				 */
  				if (!net_eq(dev_net(t->dev), net))
  					unregister_netdevice_queue(t->dev,
  								   head);
c12b395a4   xeb@mail.ru   gre: Support GRE ...
1506
1507
1508
1509
1510
1511
1512
1513
1514
  				t = rtnl_dereference(t->next);
  			}
  		}
  	}
  }
  
  static int __net_init ip6gre_init_net(struct net *net)
  {
  	struct ip6gre_net *ign = net_generic(net, ip6gre_net_id);
46ef5b89e   Wei Yongjun   ip6_gre: fix null...
1515
  	struct net_device *ndev;
c12b395a4   xeb@mail.ru   gre: Support GRE ...
1516
  	int err;
79134e6ce   Eric Dumazet   net: do not creat...
1517
1518
  	if (!net_has_fallback_tunnels(net))
  		return 0;
46ef5b89e   Wei Yongjun   ip6_gre: fix null...
1519
1520
1521
  	ndev = alloc_netdev(sizeof(struct ip6_tnl), "ip6gre0",
  			    NET_NAME_UNKNOWN, ip6gre_tunnel_setup);
  	if (!ndev) {
c12b395a4   xeb@mail.ru   gre: Support GRE ...
1522
1523
1524
  		err = -ENOMEM;
  		goto err_alloc_dev;
  	}
46ef5b89e   Wei Yongjun   ip6_gre: fix null...
1525
  	ign->fb_tunnel_dev = ndev;
c12b395a4   xeb@mail.ru   gre: Support GRE ...
1526
  	dev_net_set(ign->fb_tunnel_dev, net);
22f08069e   Nicolas Dichtel   ip6gre: add x-net...
1527
1528
1529
1530
  	/* FB netdevice is special: we have one, and only one per netns.
  	 * Allowing to move it to another netns is clearly unsafe.
  	 */
  	ign->fb_tunnel_dev->features |= NETIF_F_NETNS_LOCAL;
c12b395a4   xeb@mail.ru   gre: Support GRE ...
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
  
  	ip6gre_fb_tunnel_init(ign->fb_tunnel_dev);
  	ign->fb_tunnel_dev->rtnl_link_ops = &ip6gre_link_ops;
  
  	err = register_netdev(ign->fb_tunnel_dev);
  	if (err)
  		goto err_reg_dev;
  
  	rcu_assign_pointer(ign->tunnels_wc[0],
  			   netdev_priv(ign->fb_tunnel_dev));
  	return 0;
  
  err_reg_dev:
46ef5b89e   Wei Yongjun   ip6_gre: fix null...
1544
  	free_netdev(ndev);
c12b395a4   xeb@mail.ru   gre: Support GRE ...
1545
1546
1547
  err_alloc_dev:
  	return err;
  }
bb401caef   Eric Dumazet   ipv6: speedup ipv...
1548
  static void __net_exit ip6gre_exit_batch_net(struct list_head *net_list)
c12b395a4   xeb@mail.ru   gre: Support GRE ...
1549
  {
bb401caef   Eric Dumazet   ipv6: speedup ipv...
1550
  	struct net *net;
c12b395a4   xeb@mail.ru   gre: Support GRE ...
1551
  	LIST_HEAD(list);
c12b395a4   xeb@mail.ru   gre: Support GRE ...
1552
  	rtnl_lock();
bb401caef   Eric Dumazet   ipv6: speedup ipv...
1553
1554
  	list_for_each_entry(net, net_list, exit_list)
  		ip6gre_destroy_tunnels(net, &list);
c12b395a4   xeb@mail.ru   gre: Support GRE ...
1555
1556
1557
1558
1559
1560
  	unregister_netdevice_many(&list);
  	rtnl_unlock();
  }
  
  static struct pernet_operations ip6gre_net_ops = {
  	.init = ip6gre_init_net,
bb401caef   Eric Dumazet   ipv6: speedup ipv...
1561
  	.exit_batch = ip6gre_exit_batch_net,
c12b395a4   xeb@mail.ru   gre: Support GRE ...
1562
1563
1564
  	.id   = &ip6gre_net_id,
  	.size = sizeof(struct ip6gre_net),
  };
a8b8a889e   Matthias Schiffer   net: add netlink_...
1565
1566
  static int ip6gre_tunnel_validate(struct nlattr *tb[], struct nlattr *data[],
  				  struct netlink_ext_ack *extack)
c12b395a4   xeb@mail.ru   gre: Support GRE ...
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
  {
  	__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;
  }
a8b8a889e   Matthias Schiffer   net: add netlink_...
1583
1584
  static int ip6gre_tap_validate(struct nlattr *tb[], struct nlattr *data[],
  			       struct netlink_ext_ack *extack)
c12b395a4   xeb@mail.ru   gre: Support GRE ...
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
  {
  	struct in6_addr 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]) {
67b61f6c1   Jiri Benc   netlink: implemen...
1599
  		daddr = nla_get_in6_addr(data[IFLA_GRE_REMOTE]);
c12b395a4   xeb@mail.ru   gre: Support GRE ...
1600
1601
1602
1603
1604
  		if (ipv6_addr_any(&daddr))
  			return -EINVAL;
  	}
  
  out:
a8b8a889e   Matthias Schiffer   net: add netlink_...
1605
  	return ip6gre_tunnel_validate(tb, data, extack);
c12b395a4   xeb@mail.ru   gre: Support GRE ...
1606
  }
5a963eb61   William Tu   ip6_gre: Add ERSP...
1607
1608
1609
1610
  static int ip6erspan_tap_validate(struct nlattr *tb[], struct nlattr *data[],
  				  struct netlink_ext_ack *extack)
  {
  	__be16 flags = 0;
94d7d8f29   William Tu   ip6_gre: add ersp...
1611
  	int ret, ver = 0;
5a963eb61   William Tu   ip6_gre: Add ERSP...
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635
1636
1637
1638
  
  	if (!data)
  		return 0;
  
  	ret = ip6gre_tap_validate(tb, data, extack);
  	if (ret)
  		return ret;
  
  	/* ERSPAN should only have GRE sequence and key flag */
  	if (data[IFLA_GRE_OFLAGS])
  		flags |= nla_get_be16(data[IFLA_GRE_OFLAGS]);
  	if (data[IFLA_GRE_IFLAGS])
  		flags |= nla_get_be16(data[IFLA_GRE_IFLAGS]);
  	if (!data[IFLA_GRE_COLLECT_METADATA] &&
  	    flags != (GRE_SEQ | GRE_KEY))
  		return -EINVAL;
  
  	/* ERSPAN Session ID only has 10-bit. Since we reuse
  	 * 32-bit key field as ID, check it's range.
  	 */
  	if (data[IFLA_GRE_IKEY] &&
  	    (ntohl(nla_get_be32(data[IFLA_GRE_IKEY])) & ~ID_MASK))
  		return -EINVAL;
  
  	if (data[IFLA_GRE_OKEY] &&
  	    (ntohl(nla_get_be32(data[IFLA_GRE_OKEY])) & ~ID_MASK))
  		return -EINVAL;
94d7d8f29   William Tu   ip6_gre: add ersp...
1639
1640
1641
  	if (data[IFLA_GRE_ERSPAN_VER]) {
  		ver = nla_get_u8(data[IFLA_GRE_ERSPAN_VER]);
  		if (ver != 1 && ver != 2)
5a963eb61   William Tu   ip6_gre: Add ERSP...
1642
1643
  			return -EINVAL;
  	}
94d7d8f29   William Tu   ip6_gre: add ersp...
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
  
  	if (ver == 1) {
  		if (data[IFLA_GRE_ERSPAN_INDEX]) {
  			u32 index = nla_get_u32(data[IFLA_GRE_ERSPAN_INDEX]);
  
  			if (index & ~INDEX_MASK)
  				return -EINVAL;
  		}
  	} else if (ver == 2) {
  		if (data[IFLA_GRE_ERSPAN_DIR]) {
  			u16 dir = nla_get_u8(data[IFLA_GRE_ERSPAN_DIR]);
  
  			if (dir & ~(DIR_MASK >> DIR_OFFSET))
  				return -EINVAL;
  		}
  
  		if (data[IFLA_GRE_ERSPAN_HWID]) {
  			u16 hwid = nla_get_u16(data[IFLA_GRE_ERSPAN_HWID]);
  
  			if (hwid & ~(HWID_MASK >> HWID_OFFSET))
  				return -EINVAL;
  		}
  	}
5a963eb61   William Tu   ip6_gre: Add ERSP...
1667
1668
  	return 0;
  }
c12b395a4   xeb@mail.ru   gre: Support GRE ...
1669

4974d5f67   Lorenzo Bianconi   net: ip6_gre: ini...
1670
1671
1672
  static void ip6erspan_set_version(struct nlattr *data[],
  				  struct __ip6_tnl_parm *parms)
  {
efcc9bcaf   Lorenzo Bianconi   net: ip6_gre: fix...
1673
1674
  	if (!data)
  		return;
4974d5f67   Lorenzo Bianconi   net: ip6_gre: ini...
1675
1676
1677
1678
1679
1680
1681
1682
1683
1684
1685
1686
1687
1688
  	parms->erspan_ver = 1;
  	if (data[IFLA_GRE_ERSPAN_VER])
  		parms->erspan_ver = nla_get_u8(data[IFLA_GRE_ERSPAN_VER]);
  
  	if (parms->erspan_ver == 1) {
  		if (data[IFLA_GRE_ERSPAN_INDEX])
  			parms->index = nla_get_u32(data[IFLA_GRE_ERSPAN_INDEX]);
  	} else if (parms->erspan_ver == 2) {
  		if (data[IFLA_GRE_ERSPAN_DIR])
  			parms->dir = nla_get_u8(data[IFLA_GRE_ERSPAN_DIR]);
  		if (data[IFLA_GRE_ERSPAN_HWID])
  			parms->hwid = nla_get_u16(data[IFLA_GRE_ERSPAN_HWID]);
  	}
  }
c12b395a4   xeb@mail.ru   gre: Support GRE ...
1689
1690
1691
1692
1693
1694
1695
1696
1697
1698
1699
1700
  static void ip6gre_netlink_parms(struct nlattr *data[],
  				struct __ip6_tnl_parm *parms)
  {
  	memset(parms, 0, sizeof(*parms));
  
  	if (!data)
  		return;
  
  	if (data[IFLA_GRE_LINK])
  		parms->link = nla_get_u32(data[IFLA_GRE_LINK]);
  
  	if (data[IFLA_GRE_IFLAGS])
f41fe3c2a   Tom Herbert   gre6: Fix flag tr...
1701
1702
  		parms->i_flags = gre_flags_to_tnl_flags(
  				nla_get_be16(data[IFLA_GRE_IFLAGS]));
c12b395a4   xeb@mail.ru   gre: Support GRE ...
1703
1704
  
  	if (data[IFLA_GRE_OFLAGS])
f41fe3c2a   Tom Herbert   gre6: Fix flag tr...
1705
1706
  		parms->o_flags = gre_flags_to_tnl_flags(
  				nla_get_be16(data[IFLA_GRE_OFLAGS]));
c12b395a4   xeb@mail.ru   gre: Support GRE ...
1707
1708
1709
1710
1711
1712
1713
1714
  
  	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])
67b61f6c1   Jiri Benc   netlink: implemen...
1715
  		parms->laddr = nla_get_in6_addr(data[IFLA_GRE_LOCAL]);
c12b395a4   xeb@mail.ru   gre: Support GRE ...
1716
1717
  
  	if (data[IFLA_GRE_REMOTE])
67b61f6c1   Jiri Benc   netlink: implemen...
1718
  		parms->raddr = nla_get_in6_addr(data[IFLA_GRE_REMOTE]);
c12b395a4   xeb@mail.ru   gre: Support GRE ...
1719
1720
1721
1722
1723
1724
1725
1726
  
  	if (data[IFLA_GRE_TTL])
  		parms->hop_limit = nla_get_u8(data[IFLA_GRE_TTL]);
  
  	if (data[IFLA_GRE_ENCAP_LIMIT])
  		parms->encap_limit = nla_get_u8(data[IFLA_GRE_ENCAP_LIMIT]);
  
  	if (data[IFLA_GRE_FLOWINFO])
c2675de44   Lance Richardson   gre: use nla_get_...
1727
  		parms->flowinfo = nla_get_be32(data[IFLA_GRE_FLOWINFO]);
c12b395a4   xeb@mail.ru   gre: Support GRE ...
1728
1729
1730
  
  	if (data[IFLA_GRE_FLAGS])
  		parms->flags = nla_get_u32(data[IFLA_GRE_FLAGS]);
0a473b82c   Craig Gallek   ip6_tunnel: Allow...
1731
1732
1733
  
  	if (data[IFLA_GRE_FWMARK])
  		parms->fwmark = nla_get_u32(data[IFLA_GRE_FWMARK]);
5a963eb61   William Tu   ip6_gre: Add ERSP...
1734

6712abc16   William Tu   ip6_gre: add ip6 ...
1735
1736
  	if (data[IFLA_GRE_COLLECT_METADATA])
  		parms->collect_md = true;
c12b395a4   xeb@mail.ru   gre: Support GRE ...
1737
1738
1739
1740
  }
  
  static int ip6gre_tap_init(struct net_device *dev)
  {
a3c119d39   Martin KaFai Lau   ipv6: Refactor co...
1741
  	int ret;
c12b395a4   xeb@mail.ru   gre: Support GRE ...
1742

a3c119d39   Martin KaFai Lau   ipv6: Refactor co...
1743
1744
1745
  	ret = ip6gre_tunnel_init_common(dev);
  	if (ret)
  		return ret;
c12b395a4   xeb@mail.ru   gre: Support GRE ...
1746

0a46baaf6   Shweta Choudaha   ip6gre: Allow liv...
1747
  	dev->priv_flags |= IFF_LIVE_ADDR_CHANGE;
c12b395a4   xeb@mail.ru   gre: Support GRE ...
1748
1749
1750
1751
1752
1753
1754
1755
1756
  	return 0;
  }
  
  static const struct net_device_ops ip6gre_tap_netdev_ops = {
  	.ndo_init = ip6gre_tap_init,
  	.ndo_uninit = ip6gre_tunnel_uninit,
  	.ndo_start_xmit = ip6gre_tunnel_xmit,
  	.ndo_set_mac_address = eth_mac_addr,
  	.ndo_validate_addr = eth_validate_addr,
b05229f44   Tom Herbert   gre6: Cleanup GRE...
1757
  	.ndo_change_mtu = ip6_tnl_change_mtu,
f61dd388a   Pravin B Shelar   Tunneling: use IP...
1758
  	.ndo_get_stats64 = ip_tunnel_get_stats64,
ecf2c06a8   Nicolas Dichtel   ip6tnl,gre6,vti6:...
1759
  	.ndo_get_iflink = ip6_tnl_get_iflink,
c12b395a4   xeb@mail.ru   gre: Support GRE ...
1760
  };
2d665034f   Petr Machata   net: ip6_gre: Fix...
1761
1762
1763
1764
1765
1766
1767
1768
1769
  static int ip6erspan_calc_hlen(struct ip6_tnl *tunnel)
  {
  	int t_hlen;
  
  	tunnel->tun_hlen = 8;
  	tunnel->hlen = tunnel->tun_hlen + tunnel->encap_hlen +
  		       erspan_hdr_len(tunnel->parms.erspan_ver);
  
  	t_hlen = tunnel->hlen + sizeof(struct ipv6hdr);
eb95f52fc   Maria Pasechnik   net: ipv6_gre: Fi...
1770
  	tunnel->dev->needed_headroom = LL_MAX_HEADER + t_hlen;
2d665034f   Petr Machata   net: ip6_gre: Fix...
1771
1772
  	return t_hlen;
  }
5a963eb61   William Tu   ip6_gre: Add ERSP...
1773
1774
1775
1776
1777
1778
1779
1780
1781
1782
1783
1784
1785
1786
1787
1788
1789
  static int ip6erspan_tap_init(struct net_device *dev)
  {
  	struct ip6_tnl *tunnel;
  	int t_hlen;
  	int ret;
  
  	tunnel = netdev_priv(dev);
  
  	tunnel->dev = dev;
  	tunnel->net = dev_net(dev);
  	strcpy(tunnel->parms.name, dev->name);
  
  	dev->tstats = netdev_alloc_pcpu_stats(struct pcpu_sw_netstats);
  	if (!dev->tstats)
  		return -ENOMEM;
  
  	ret = dst_cache_init(&tunnel->dst_cache, GFP_KERNEL);
0c1dd2a16   Eran Ben Elisha   net: ipv6/gre: Ad...
1790
1791
1792
1793
1794
1795
  	if (ret)
  		goto cleanup_alloc_pcpu_stats;
  
  	ret = gro_cells_init(&tunnel->gro_cells, dev);
  	if (ret)
  		goto cleanup_dst_cache_init;
5a963eb61   William Tu   ip6_gre: Add ERSP...
1796

2d665034f   Petr Machata   net: ip6_gre: Fix...
1797
  	t_hlen = ip6erspan_calc_hlen(tunnel);
5a963eb61   William Tu   ip6_gre: Add ERSP...
1798
1799
1800
1801
1802
1803
1804
  	dev->mtu = ETH_DATA_LEN - t_hlen;
  	if (dev->type == ARPHRD_ETHER)
  		dev->mtu -= ETH_HLEN;
  	if (!(tunnel->parms.flags & IP6_TNL_F_IGN_ENCAP_LIMIT))
  		dev->mtu -= 8;
  
  	dev->priv_flags |= IFF_LIVE_ADDR_CHANGE;
2d665034f   Petr Machata   net: ip6_gre: Fix...
1805
  	ip6erspan_tnl_link_config(tunnel, 1);
5a963eb61   William Tu   ip6_gre: Add ERSP...
1806
1807
  
  	return 0;
0c1dd2a16   Eran Ben Elisha   net: ipv6/gre: Ad...
1808
1809
1810
1811
1812
1813
1814
  
  cleanup_dst_cache_init:
  	dst_cache_destroy(&tunnel->dst_cache);
  cleanup_alloc_pcpu_stats:
  	free_percpu(dev->tstats);
  	dev->tstats = NULL;
  	return ret;
5a963eb61   William Tu   ip6_gre: Add ERSP...
1815
1816
1817
1818
  }
  
  static const struct net_device_ops ip6erspan_netdev_ops = {
  	.ndo_init =		ip6erspan_tap_init,
b80d0b93b   William Tu   net: ip6_gre: fix...
1819
  	.ndo_uninit =		ip6erspan_tunnel_uninit,
5a963eb61   William Tu   ip6_gre: Add ERSP...
1820
1821
1822
1823
1824
1825
1826
  	.ndo_start_xmit =	ip6erspan_tunnel_xmit,
  	.ndo_set_mac_address =	eth_mac_addr,
  	.ndo_validate_addr =	eth_validate_addr,
  	.ndo_change_mtu =	ip6_tnl_change_mtu,
  	.ndo_get_stats64 =	ip_tunnel_get_stats64,
  	.ndo_get_iflink =	ip6_tnl_get_iflink,
  };
c12b395a4   xeb@mail.ru   gre: Support GRE ...
1827
1828
1829
1830
  static void ip6gre_tap_setup(struct net_device *dev)
  {
  
  	ether_setup(dev);
2c52129a7   Xin Long   ip6_gre: remove t...
1831
  	dev->max_mtu = 0;
c12b395a4   xeb@mail.ru   gre: Support GRE ...
1832
  	dev->netdev_ops = &ip6gre_tap_netdev_ops;
cf124db56   David S. Miller   net: Fix inconsis...
1833
1834
  	dev->needs_free_netdev = true;
  	dev->priv_destructor = ip6gre_dev_free;
c12b395a4   xeb@mail.ru   gre: Support GRE ...
1835

d13b161c2   Jiri Benc   gre: clear IFF_TX...
1836
  	dev->priv_flags &= ~IFF_TX_SKB_SHARING;
0a46baaf6   Shweta Choudaha   ip6gre: Allow liv...
1837
  	dev->priv_flags |= IFF_LIVE_ADDR_CHANGE;
2d40557cc   Xin Long   ip6_gre: ip6gre_t...
1838
  	netif_keep_dst(dev);
c12b395a4   xeb@mail.ru   gre: Support GRE ...
1839
  }
1faf3d9f7   Tom Herbert   ip6_gre: Add supp...
1840
1841
1842
1843
1844
1845
1846
1847
1848
1849
1850
1851
1852
1853
1854
1855
1856
1857
1858
1859
1860
1861
1862
1863
1864
1865
1866
1867
1868
1869
1870
1871
  static bool ip6gre_netlink_encap_parms(struct nlattr *data[],
  				       struct ip_tunnel_encap *ipencap)
  {
  	bool ret = false;
  
  	memset(ipencap, 0, sizeof(*ipencap));
  
  	if (!data)
  		return ret;
  
  	if (data[IFLA_GRE_ENCAP_TYPE]) {
  		ret = true;
  		ipencap->type = nla_get_u16(data[IFLA_GRE_ENCAP_TYPE]);
  	}
  
  	if (data[IFLA_GRE_ENCAP_FLAGS]) {
  		ret = true;
  		ipencap->flags = nla_get_u16(data[IFLA_GRE_ENCAP_FLAGS]);
  	}
  
  	if (data[IFLA_GRE_ENCAP_SPORT]) {
  		ret = true;
  		ipencap->sport = nla_get_be16(data[IFLA_GRE_ENCAP_SPORT]);
  	}
  
  	if (data[IFLA_GRE_ENCAP_DPORT]) {
  		ret = true;
  		ipencap->dport = nla_get_be16(data[IFLA_GRE_ENCAP_DPORT]);
  	}
  
  	return ret;
  }
7fa38a7c8   Petr Machata   net: ip6_gre: Spl...
1872
1873
1874
  static int ip6gre_newlink_common(struct net *src_net, struct net_device *dev,
  				 struct nlattr *tb[], struct nlattr *data[],
  				 struct netlink_ext_ack *extack)
c12b395a4   xeb@mail.ru   gre: Support GRE ...
1875
1876
  {
  	struct ip6_tnl *nt;
1faf3d9f7   Tom Herbert   ip6_gre: Add supp...
1877
  	struct ip_tunnel_encap ipencap;
c12b395a4   xeb@mail.ru   gre: Support GRE ...
1878
1879
1880
  	int err;
  
  	nt = netdev_priv(dev);
1faf3d9f7   Tom Herbert   ip6_gre: Add supp...
1881
1882
1883
1884
1885
1886
1887
  
  	if (ip6gre_netlink_encap_parms(data, &ipencap)) {
  		int err = ip6_tnl_encap_setup(nt, &ipencap);
  
  		if (err < 0)
  			return err;
  	}
c12b395a4   xeb@mail.ru   gre: Support GRE ...
1888
1889
1890
1891
  	if (dev->type == ARPHRD_ETHER && !tb[IFLA_ADDRESS])
  		eth_hw_addr_random(dev);
  
  	nt->dev = dev;
0bd876282   Nicolas Dichtel   ip6tnl: add x-net...
1892
  	nt->net = dev_net(dev);
c12b395a4   xeb@mail.ru   gre: Support GRE ...
1893

c12b395a4   xeb@mail.ru   gre: Support GRE ...
1894
1895
1896
  	err = register_netdevice(dev);
  	if (err)
  		goto out;
128bb975d   Alexey Kodanev   ip6_gre: init dev...
1897
1898
  	if (tb[IFLA_MTU])
  		ip6_tnl_change_mtu(dev, nla_get_u32(tb[IFLA_MTU]));
c12b395a4   xeb@mail.ru   gre: Support GRE ...
1899
  	dev_hold(dev);
c12b395a4   xeb@mail.ru   gre: Support GRE ...
1900
1901
1902
1903
  
  out:
  	return err;
  }
7fa38a7c8   Petr Machata   net: ip6_gre: Spl...
1904
1905
1906
1907
  static int ip6gre_newlink(struct net *src_net, struct net_device *dev,
  			  struct nlattr *tb[], struct nlattr *data[],
  			  struct netlink_ext_ack *extack)
  {
7fa38a7c8   Petr Machata   net: ip6_gre: Spl...
1908
1909
  	struct ip6_tnl *nt = netdev_priv(dev);
  	struct net *net = dev_net(dev);
b80d0b93b   William Tu   net: ip6_gre: fix...
1910
1911
1912
1913
1914
1915
1916
1917
1918
1919
1920
1921
1922
  	struct ip6gre_net *ign;
  	int err;
  
  	ip6gre_netlink_parms(data, &nt->parms);
  	ign = net_generic(net, ip6gre_net_id);
  
  	if (nt->parms.collect_md) {
  		if (rtnl_dereference(ign->collect_md_tun))
  			return -EEXIST;
  	} else {
  		if (ip6gre_tunnel_find(net, &nt->parms, dev->type))
  			return -EEXIST;
  	}
7fa38a7c8   Petr Machata   net: ip6_gre: Spl...
1923

b80d0b93b   William Tu   net: ip6_gre: fix...
1924
  	err = ip6gre_newlink_common(src_net, dev, tb, data, extack);
7fa38a7c8   Petr Machata   net: ip6_gre: Spl...
1925
1926
  	if (!err) {
  		ip6gre_tnl_link_config(nt, !tb[IFLA_MTU]);
b80d0b93b   William Tu   net: ip6_gre: fix...
1927
  		ip6gre_tunnel_link_md(ign, nt);
7fa38a7c8   Petr Machata   net: ip6_gre: Spl...
1928
1929
1930
1931
  		ip6gre_tunnel_link(net_generic(net, ip6gre_net_id), nt);
  	}
  	return err;
  }
c8632fc30   Petr Machata   net: ip6_gre: Spl...
1932
1933
1934
1935
  static struct ip6_tnl *
  ip6gre_changelink_common(struct net_device *dev, struct nlattr *tb[],
  			 struct nlattr *data[], struct __ip6_tnl_parm *p_p,
  			 struct netlink_ext_ack *extack)
c12b395a4   xeb@mail.ru   gre: Support GRE ...
1936
  {
22f08069e   Nicolas Dichtel   ip6gre: add x-net...
1937
1938
  	struct ip6_tnl *t, *nt = netdev_priv(dev);
  	struct net *net = nt->net;
c12b395a4   xeb@mail.ru   gre: Support GRE ...
1939
  	struct ip6gre_net *ign = net_generic(net, ip6gre_net_id);
1faf3d9f7   Tom Herbert   ip6_gre: Add supp...
1940
  	struct ip_tunnel_encap ipencap;
c12b395a4   xeb@mail.ru   gre: Support GRE ...
1941
1942
  
  	if (dev == ign->fb_tunnel_dev)
c8632fc30   Petr Machata   net: ip6_gre: Spl...
1943
  		return ERR_PTR(-EINVAL);
c12b395a4   xeb@mail.ru   gre: Support GRE ...
1944

1faf3d9f7   Tom Herbert   ip6_gre: Add supp...
1945
1946
1947
1948
  	if (ip6gre_netlink_encap_parms(data, &ipencap)) {
  		int err = ip6_tnl_encap_setup(nt, &ipencap);
  
  		if (err < 0)
c8632fc30   Petr Machata   net: ip6_gre: Spl...
1949
  			return ERR_PTR(err);
1faf3d9f7   Tom Herbert   ip6_gre: Add supp...
1950
  	}
c8632fc30   Petr Machata   net: ip6_gre: Spl...
1951
  	ip6gre_netlink_parms(data, p_p);
c12b395a4   xeb@mail.ru   gre: Support GRE ...
1952

c8632fc30   Petr Machata   net: ip6_gre: Spl...
1953
  	t = ip6gre_tunnel_locate(net, p_p, 0);
c12b395a4   xeb@mail.ru   gre: Support GRE ...
1954
1955
1956
  
  	if (t) {
  		if (t->dev != dev)
c8632fc30   Petr Machata   net: ip6_gre: Spl...
1957
  			return ERR_PTR(-EEXIST);
c12b395a4   xeb@mail.ru   gre: Support GRE ...
1958
1959
  	} else {
  		t = nt;
c12b395a4   xeb@mail.ru   gre: Support GRE ...
1960
  	}
c8632fc30   Petr Machata   net: ip6_gre: Spl...
1961
1962
1963
1964
1965
1966
1967
  	return t;
  }
  
  static int ip6gre_changelink(struct net_device *dev, struct nlattr *tb[],
  			     struct nlattr *data[],
  			     struct netlink_ext_ack *extack)
  {
ab5098fa2   Olivier Matz   ip6_gre: fix tunn...
1968
1969
  	struct ip6_tnl *t = netdev_priv(dev);
  	struct ip6gre_net *ign = net_generic(t->net, ip6gre_net_id);
c8632fc30   Petr Machata   net: ip6_gre: Spl...
1970
  	struct __ip6_tnl_parm p;
c8632fc30   Petr Machata   net: ip6_gre: Spl...
1971
1972
1973
1974
  
  	t = ip6gre_changelink_common(dev, tb, data, &p, extack);
  	if (IS_ERR(t))
  		return PTR_ERR(t);
b80d0b93b   William Tu   net: ip6_gre: fix...
1975
  	ip6gre_tunnel_unlink_md(ign, t);
6a61d4dbf   Nicolas Dichtel   gre6: allow to up...
1976
1977
  	ip6gre_tunnel_unlink(ign, t);
  	ip6gre_tnl_change(t, &p, !tb[IFLA_MTU]);
b80d0b93b   William Tu   net: ip6_gre: fix...
1978
  	ip6gre_tunnel_link_md(ign, t);
6a61d4dbf   Nicolas Dichtel   gre6: allow to up...
1979
  	ip6gre_tunnel_link(ign, t);
c12b395a4   xeb@mail.ru   gre: Support GRE ...
1980
1981
  	return 0;
  }
54d63f787   Nicolas Dichtel   ip6_gre: don't al...
1982
1983
1984
1985
1986
1987
1988
1989
  static void ip6gre_dellink(struct net_device *dev, struct list_head *head)
  {
  	struct net *net = dev_net(dev);
  	struct ip6gre_net *ign = net_generic(net, ip6gre_net_id);
  
  	if (dev != ign->fb_tunnel_dev)
  		unregister_netdevice_queue(dev, head);
  }
c12b395a4   xeb@mail.ru   gre: Support GRE ...
1990
1991
1992
1993
1994
1995
1996
1997
1998
1999
2000
2001
2002
2003
  static size_t ip6gre_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 */
a37541331   Nicolas Dichtel   gre6: fix rtnl du...
2004
  		nla_total_size(sizeof(struct in6_addr)) +
c12b395a4   xeb@mail.ru   gre: Support GRE ...
2005
  		/* IFLA_GRE_REMOTE */
a37541331   Nicolas Dichtel   gre6: fix rtnl du...
2006
  		nla_total_size(sizeof(struct in6_addr)) +
c12b395a4   xeb@mail.ru   gre: Support GRE ...
2007
2008
  		/* IFLA_GRE_TTL */
  		nla_total_size(1) +
c12b395a4   xeb@mail.ru   gre: Support GRE ...
2009
2010
2011
2012
2013
2014
  		/* IFLA_GRE_ENCAP_LIMIT */
  		nla_total_size(1) +
  		/* IFLA_GRE_FLOWINFO */
  		nla_total_size(4) +
  		/* IFLA_GRE_FLAGS */
  		nla_total_size(4) +
1faf3d9f7   Tom Herbert   ip6_gre: Add supp...
2015
2016
2017
2018
2019
2020
2021
2022
  		/* IFLA_GRE_ENCAP_TYPE */
  		nla_total_size(2) +
  		/* IFLA_GRE_ENCAP_FLAGS */
  		nla_total_size(2) +
  		/* IFLA_GRE_ENCAP_SPORT */
  		nla_total_size(2) +
  		/* IFLA_GRE_ENCAP_DPORT */
  		nla_total_size(2) +
6712abc16   William Tu   ip6_gre: add ip6 ...
2023
2024
  		/* IFLA_GRE_COLLECT_METADATA */
  		nla_total_size(0) +
0a473b82c   Craig Gallek   ip6_tunnel: Allow...
2025
2026
  		/* IFLA_GRE_FWMARK */
  		nla_total_size(4) +
5a963eb61   William Tu   ip6_gre: Add ERSP...
2027
2028
  		/* IFLA_GRE_ERSPAN_INDEX */
  		nla_total_size(4) +
c12b395a4   xeb@mail.ru   gre: Support GRE ...
2029
2030
2031
2032
2033
2034
2035
  		0;
  }
  
  static int ip6gre_fill_info(struct sk_buff *skb, const struct net_device *dev)
  {
  	struct ip6_tnl *t = netdev_priv(dev);
  	struct __ip6_tnl_parm *p = &t->parms;
c706863bc   Lorenzo Bianconi   net: ip6_gre: alw...
2036
  	__be16 o_flags = p->o_flags;
103d0244d   Lorenzo Bianconi   net: ip6_gre: do ...
2037
2038
2039
2040
2041
2042
2043
2044
2045
2046
2047
2048
2049
2050
2051
2052
2053
  	if (p->erspan_ver == 1 || p->erspan_ver == 2) {
  		if (!p->collect_md)
  			o_flags |= TUNNEL_KEY;
  
  		if (nla_put_u8(skb, IFLA_GRE_ERSPAN_VER, p->erspan_ver))
  			goto nla_put_failure;
  
  		if (p->erspan_ver == 1) {
  			if (nla_put_u32(skb, IFLA_GRE_ERSPAN_INDEX, p->index))
  				goto nla_put_failure;
  		} else {
  			if (nla_put_u8(skb, IFLA_GRE_ERSPAN_DIR, p->dir))
  				goto nla_put_failure;
  			if (nla_put_u16(skb, IFLA_GRE_ERSPAN_HWID, p->hwid))
  				goto nla_put_failure;
  		}
  	}
c12b395a4   xeb@mail.ru   gre: Support GRE ...
2054
2055
  
  	if (nla_put_u32(skb, IFLA_GRE_LINK, p->link) ||
f41fe3c2a   Tom Herbert   gre6: Fix flag tr...
2056
2057
2058
  	    nla_put_be16(skb, IFLA_GRE_IFLAGS,
  			 gre_tnl_flags_to_gre_flags(p->i_flags)) ||
  	    nla_put_be16(skb, IFLA_GRE_OFLAGS,
c706863bc   Lorenzo Bianconi   net: ip6_gre: alw...
2059
  			 gre_tnl_flags_to_gre_flags(o_flags)) ||
c12b395a4   xeb@mail.ru   gre: Support GRE ...
2060
2061
  	    nla_put_be32(skb, IFLA_GRE_IKEY, p->i_key) ||
  	    nla_put_be32(skb, IFLA_GRE_OKEY, p->o_key) ||
930345ea6   Jiri Benc   netlink: implemen...
2062
2063
  	    nla_put_in6_addr(skb, IFLA_GRE_LOCAL, &p->laddr) ||
  	    nla_put_in6_addr(skb, IFLA_GRE_REMOTE, &p->raddr) ||
c12b395a4   xeb@mail.ru   gre: Support GRE ...
2064
  	    nla_put_u8(skb, IFLA_GRE_TTL, p->hop_limit) ||
c12b395a4   xeb@mail.ru   gre: Support GRE ...
2065
2066
  	    nla_put_u8(skb, IFLA_GRE_ENCAP_LIMIT, p->encap_limit) ||
  	    nla_put_be32(skb, IFLA_GRE_FLOWINFO, p->flowinfo) ||
0a473b82c   Craig Gallek   ip6_tunnel: Allow...
2067
  	    nla_put_u32(skb, IFLA_GRE_FLAGS, p->flags) ||
103d0244d   Lorenzo Bianconi   net: ip6_gre: do ...
2068
  	    nla_put_u32(skb, IFLA_GRE_FWMARK, p->fwmark))
c12b395a4   xeb@mail.ru   gre: Support GRE ...
2069
  		goto nla_put_failure;
1faf3d9f7   Tom Herbert   ip6_gre: Add supp...
2070
2071
2072
2073
2074
2075
2076
2077
2078
2079
  
  	if (nla_put_u16(skb, IFLA_GRE_ENCAP_TYPE,
  			t->encap.type) ||
  	    nla_put_be16(skb, IFLA_GRE_ENCAP_SPORT,
  			 t->encap.sport) ||
  	    nla_put_be16(skb, IFLA_GRE_ENCAP_DPORT,
  			 t->encap.dport) ||
  	    nla_put_u16(skb, IFLA_GRE_ENCAP_FLAGS,
  			t->encap.flags))
  		goto nla_put_failure;
6712abc16   William Tu   ip6_gre: add ip6 ...
2080
2081
2082
2083
  	if (p->collect_md) {
  		if (nla_put_flag(skb, IFLA_GRE_COLLECT_METADATA))
  			goto nla_put_failure;
  	}
c12b395a4   xeb@mail.ru   gre: Support GRE ...
2084
2085
2086
2087
2088
2089
2090
2091
2092
2093
2094
2095
  	return 0;
  
  nla_put_failure:
  	return -EMSGSIZE;
  }
  
  static const struct nla_policy ip6gre_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 },
c593642c8   Pankaj Bharadiya   treewide: Use siz...
2096
2097
  	[IFLA_GRE_LOCAL]       = { .len = sizeof_field(struct ipv6hdr, saddr) },
  	[IFLA_GRE_REMOTE]      = { .len = sizeof_field(struct ipv6hdr, daddr) },
c12b395a4   xeb@mail.ru   gre: Support GRE ...
2098
2099
2100
2101
  	[IFLA_GRE_TTL]         = { .type = NLA_U8 },
  	[IFLA_GRE_ENCAP_LIMIT] = { .type = NLA_U8 },
  	[IFLA_GRE_FLOWINFO]    = { .type = NLA_U32 },
  	[IFLA_GRE_FLAGS]       = { .type = NLA_U32 },
1faf3d9f7   Tom Herbert   ip6_gre: Add supp...
2102
2103
2104
2105
  	[IFLA_GRE_ENCAP_TYPE]   = { .type = NLA_U16 },
  	[IFLA_GRE_ENCAP_FLAGS]  = { .type = NLA_U16 },
  	[IFLA_GRE_ENCAP_SPORT]  = { .type = NLA_U16 },
  	[IFLA_GRE_ENCAP_DPORT]  = { .type = NLA_U16 },
6712abc16   William Tu   ip6_gre: add ip6 ...
2106
  	[IFLA_GRE_COLLECT_METADATA] = { .type = NLA_FLAG },
0a473b82c   Craig Gallek   ip6_tunnel: Allow...
2107
  	[IFLA_GRE_FWMARK]       = { .type = NLA_U32 },
5a963eb61   William Tu   ip6_gre: Add ERSP...
2108
  	[IFLA_GRE_ERSPAN_INDEX] = { .type = NLA_U32 },
94d7d8f29   William Tu   ip6_gre: add ersp...
2109
2110
2111
  	[IFLA_GRE_ERSPAN_VER]	= { .type = NLA_U8 },
  	[IFLA_GRE_ERSPAN_DIR]	= { .type = NLA_U8 },
  	[IFLA_GRE_ERSPAN_HWID]	= { .type = NLA_U16 },
c12b395a4   xeb@mail.ru   gre: Support GRE ...
2112
  };
5a963eb61   William Tu   ip6_gre: Add ERSP...
2113
2114
2115
  static void ip6erspan_tap_setup(struct net_device *dev)
  {
  	ether_setup(dev);
4123f637a   Haishuang Yan   ip6erspan: remove...
2116
  	dev->max_mtu = 0;
5a963eb61   William Tu   ip6_gre: Add ERSP...
2117
2118
2119
  	dev->netdev_ops = &ip6erspan_netdev_ops;
  	dev->needs_free_netdev = true;
  	dev->priv_destructor = ip6gre_dev_free;
5a963eb61   William Tu   ip6_gre: Add ERSP...
2120
2121
2122
2123
  	dev->priv_flags &= ~IFF_TX_SKB_SHARING;
  	dev->priv_flags |= IFF_LIVE_ADDR_CHANGE;
  	netif_keep_dst(dev);
  }
2d665034f   Petr Machata   net: ip6_gre: Fix...
2124
2125
2126
2127
  static int ip6erspan_newlink(struct net *src_net, struct net_device *dev,
  			     struct nlattr *tb[], struct nlattr *data[],
  			     struct netlink_ext_ack *extack)
  {
2d665034f   Petr Machata   net: ip6_gre: Fix...
2128
2129
  	struct ip6_tnl *nt = netdev_priv(dev);
  	struct net *net = dev_net(dev);
b80d0b93b   William Tu   net: ip6_gre: fix...
2130
2131
2132
2133
  	struct ip6gre_net *ign;
  	int err;
  
  	ip6gre_netlink_parms(data, &nt->parms);
4974d5f67   Lorenzo Bianconi   net: ip6_gre: ini...
2134
  	ip6erspan_set_version(data, &nt->parms);
b80d0b93b   William Tu   net: ip6_gre: fix...
2135
2136
2137
2138
2139
2140
2141
2142
2143
  	ign = net_generic(net, ip6gre_net_id);
  
  	if (nt->parms.collect_md) {
  		if (rtnl_dereference(ign->collect_md_tun_erspan))
  			return -EEXIST;
  	} else {
  		if (ip6gre_tunnel_find(net, &nt->parms, dev->type))
  			return -EEXIST;
  	}
2d665034f   Petr Machata   net: ip6_gre: Fix...
2144

b80d0b93b   William Tu   net: ip6_gre: fix...
2145
  	err = ip6gre_newlink_common(src_net, dev, tb, data, extack);
2d665034f   Petr Machata   net: ip6_gre: Fix...
2146
2147
  	if (!err) {
  		ip6erspan_tnl_link_config(nt, !tb[IFLA_MTU]);
b80d0b93b   William Tu   net: ip6_gre: fix...
2148
  		ip6erspan_tunnel_link_md(ign, nt);
2d665034f   Petr Machata   net: ip6_gre: Fix...
2149
2150
2151
2152
2153
2154
2155
2156
2157
2158
2159
2160
2161
2162
2163
2164
2165
2166
2167
2168
2169
2170
2171
2172
2173
2174
2175
2176
2177
2178
  		ip6gre_tunnel_link(net_generic(net, ip6gre_net_id), nt);
  	}
  	return err;
  }
  
  static void ip6erspan_tnl_link_config(struct ip6_tnl *t, int set_mtu)
  {
  	ip6gre_tnl_link_config_common(t);
  	ip6gre_tnl_link_config_route(t, set_mtu, ip6erspan_calc_hlen(t));
  }
  
  static int ip6erspan_tnl_change(struct ip6_tnl *t,
  				const struct __ip6_tnl_parm *p, int set_mtu)
  {
  	ip6gre_tnl_copy_tnl_parm(t, p);
  	ip6erspan_tnl_link_config(t, set_mtu);
  	return 0;
  }
  
  static int ip6erspan_changelink(struct net_device *dev, struct nlattr *tb[],
  				struct nlattr *data[],
  				struct netlink_ext_ack *extack)
  {
  	struct ip6gre_net *ign = net_generic(dev_net(dev), ip6gre_net_id);
  	struct __ip6_tnl_parm p;
  	struct ip6_tnl *t;
  
  	t = ip6gre_changelink_common(dev, tb, data, &p, extack);
  	if (IS_ERR(t))
  		return PTR_ERR(t);
4974d5f67   Lorenzo Bianconi   net: ip6_gre: ini...
2179
  	ip6erspan_set_version(data, &p);
b80d0b93b   William Tu   net: ip6_gre: fix...
2180
  	ip6gre_tunnel_unlink_md(ign, t);
2d665034f   Petr Machata   net: ip6_gre: Fix...
2181
2182
  	ip6gre_tunnel_unlink(ign, t);
  	ip6erspan_tnl_change(t, &p, !tb[IFLA_MTU]);
b80d0b93b   William Tu   net: ip6_gre: fix...
2183
  	ip6erspan_tunnel_link_md(ign, t);
2d665034f   Petr Machata   net: ip6_gre: Fix...
2184
2185
2186
  	ip6gre_tunnel_link(ign, t);
  	return 0;
  }
c12b395a4   xeb@mail.ru   gre: Support GRE ...
2187
2188
2189
2190
2191
2192
2193
2194
2195
  static struct rtnl_link_ops ip6gre_link_ops __read_mostly = {
  	.kind		= "ip6gre",
  	.maxtype	= IFLA_GRE_MAX,
  	.policy		= ip6gre_policy,
  	.priv_size	= sizeof(struct ip6_tnl),
  	.setup		= ip6gre_tunnel_setup,
  	.validate	= ip6gre_tunnel_validate,
  	.newlink	= ip6gre_newlink,
  	.changelink	= ip6gre_changelink,
54d63f787   Nicolas Dichtel   ip6_gre: don't al...
2196
  	.dellink	= ip6gre_dellink,
c12b395a4   xeb@mail.ru   gre: Support GRE ...
2197
2198
  	.get_size	= ip6gre_get_size,
  	.fill_info	= ip6gre_fill_info,
1728d4fab   Nicolas Dichtel   tunnels: advertis...
2199
  	.get_link_net	= ip6_tnl_get_link_net,
c12b395a4   xeb@mail.ru   gre: Support GRE ...
2200
2201
2202
2203
2204
2205
2206
2207
2208
2209
2210
2211
2212
  };
  
  static struct rtnl_link_ops ip6gre_tap_ops __read_mostly = {
  	.kind		= "ip6gretap",
  	.maxtype	= IFLA_GRE_MAX,
  	.policy		= ip6gre_policy,
  	.priv_size	= sizeof(struct ip6_tnl),
  	.setup		= ip6gre_tap_setup,
  	.validate	= ip6gre_tap_validate,
  	.newlink	= ip6gre_newlink,
  	.changelink	= ip6gre_changelink,
  	.get_size	= ip6gre_get_size,
  	.fill_info	= ip6gre_fill_info,
3390e3976   Nicolas Dichtel   ip6gretap: advert...
2213
  	.get_link_net	= ip6_tnl_get_link_net,
c12b395a4   xeb@mail.ru   gre: Support GRE ...
2214
  };
5a963eb61   William Tu   ip6_gre: Add ERSP...
2215
2216
2217
2218
2219
2220
2221
  static struct rtnl_link_ops ip6erspan_tap_ops __read_mostly = {
  	.kind		= "ip6erspan",
  	.maxtype	= IFLA_GRE_MAX,
  	.policy		= ip6gre_policy,
  	.priv_size	= sizeof(struct ip6_tnl),
  	.setup		= ip6erspan_tap_setup,
  	.validate	= ip6erspan_tap_validate,
2d665034f   Petr Machata   net: ip6_gre: Fix...
2222
2223
  	.newlink	= ip6erspan_newlink,
  	.changelink	= ip6erspan_changelink,
5a963eb61   William Tu   ip6_gre: Add ERSP...
2224
2225
2226
2227
  	.get_size	= ip6gre_get_size,
  	.fill_info	= ip6gre_fill_info,
  	.get_link_net	= ip6_tnl_get_link_net,
  };
c12b395a4   xeb@mail.ru   gre: Support GRE ...
2228
2229
2230
2231
2232
2233
2234
2235
2236
2237
2238
2239
2240
2241
2242
2243
2244
2245
2246
2247
2248
2249
2250
2251
2252
2253
2254
2255
2256
  /*
   *	And now the modules code and kernel interface.
   */
  
  static int __init ip6gre_init(void)
  {
  	int err;
  
  	pr_info("GRE over IPv6 tunneling driver
  ");
  
  	err = register_pernet_device(&ip6gre_net_ops);
  	if (err < 0)
  		return err;
  
  	err = inet6_add_protocol(&ip6gre_protocol, IPPROTO_GRE);
  	if (err < 0) {
  		pr_info("%s: can't add protocol
  ", __func__);
  		goto add_proto_failed;
  	}
  
  	err = rtnl_link_register(&ip6gre_link_ops);
  	if (err < 0)
  		goto rtnl_link_failed;
  
  	err = rtnl_link_register(&ip6gre_tap_ops);
  	if (err < 0)
  		goto tap_ops_failed;
5a963eb61   William Tu   ip6_gre: Add ERSP...
2257
2258
2259
  	err = rtnl_link_register(&ip6erspan_tap_ops);
  	if (err < 0)
  		goto erspan_link_failed;
c12b395a4   xeb@mail.ru   gre: Support GRE ...
2260
2261
  out:
  	return err;
5a963eb61   William Tu   ip6_gre: Add ERSP...
2262
2263
  erspan_link_failed:
  	rtnl_link_unregister(&ip6gre_tap_ops);
c12b395a4   xeb@mail.ru   gre: Support GRE ...
2264
2265
2266
2267
2268
2269
2270
2271
2272
2273
2274
2275
2276
  tap_ops_failed:
  	rtnl_link_unregister(&ip6gre_link_ops);
  rtnl_link_failed:
  	inet6_del_protocol(&ip6gre_protocol, IPPROTO_GRE);
  add_proto_failed:
  	unregister_pernet_device(&ip6gre_net_ops);
  	goto out;
  }
  
  static void __exit ip6gre_fini(void)
  {
  	rtnl_link_unregister(&ip6gre_tap_ops);
  	rtnl_link_unregister(&ip6gre_link_ops);
5a963eb61   William Tu   ip6_gre: Add ERSP...
2277
  	rtnl_link_unregister(&ip6erspan_tap_ops);
c12b395a4   xeb@mail.ru   gre: Support GRE ...
2278
2279
2280
2281
2282
2283
2284
2285
2286
2287
  	inet6_del_protocol(&ip6gre_protocol, IPPROTO_GRE);
  	unregister_pernet_device(&ip6gre_net_ops);
  }
  
  module_init(ip6gre_init);
  module_exit(ip6gre_fini);
  MODULE_LICENSE("GPL");
  MODULE_AUTHOR("D. Kozlov (xeb@mail.ru)");
  MODULE_DESCRIPTION("GRE over IPv6 tunneling device");
  MODULE_ALIAS_RTNL_LINK("ip6gre");
5a4ee9a9a   Nicolas Dichtel   ip6gre: add a rtn...
2288
  MODULE_ALIAS_RTNL_LINK("ip6gretap");
94d7d8f29   William Tu   ip6_gre: add ersp...
2289
  MODULE_ALIAS_RTNL_LINK("ip6erspan");
c12b395a4   xeb@mail.ru   gre: Support GRE ...
2290
  MODULE_ALIAS_NETDEV("ip6gre0");