Blame view

net/ipv6/sit.c 29 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
2
3
4
5
  /*
   *	IPv6 over IPv4 tunnel device - Simple Internet Transition (SIT)
   *	Linux INET6 implementation
   *
   *	Authors:
1ab1457c4   YOSHIFUJI Hideaki   [NET] IPV6: Fix w...
6
   *	Pedro Roque		<roque@di.fc.ul.pt>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
7
8
   *	Alexey Kuznetsov	<kuznet@ms2.inr.ac.ru>
   *
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
9
10
11
12
13
14
15
16
   *	This program is free software; you can redistribute it and/or
   *      modify it under the terms of the GNU General Public License
   *      as published by the Free Software Foundation; either version
   *      2 of the License, or (at your option) any later version.
   *
   *	Changes:
   * Roger Venning <r.venning@telstra.com>:	6to4 support
   * Nate Thompson <nate@thebog.net>:		6to4 support
fadf6bf06   Templin, Fred L   [IPV6] SIT: Add P...
17
   * Fred Templin <fred.l.templin@boeing.com>:	isatap support
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
18
   */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
19
  #include <linux/module.h>
4fc268d24   Randy Dunlap   [PATCH] capable/c...
20
  #include <linux/capability.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
21
22
23
24
  #include <linux/errno.h>
  #include <linux/types.h>
  #include <linux/socket.h>
  #include <linux/sockios.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
25
26
27
28
29
  #include <linux/net.h>
  #include <linux/in6.h>
  #include <linux/netdevice.h>
  #include <linux/if_arp.h>
  #include <linux/icmp.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
30
  #include <linux/slab.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
31
32
33
  #include <asm/uaccess.h>
  #include <linux/init.h>
  #include <linux/netfilter_ipv4.h>
46f25dffb   Kris Katterjohn   [NET]: Change 150...
34
  #include <linux/if_ether.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
  
  #include <net/sock.h>
  #include <net/snmp.h>
  
  #include <net/ipv6.h>
  #include <net/protocol.h>
  #include <net/transp_v6.h>
  #include <net/ip6_fib.h>
  #include <net/ip6_route.h>
  #include <net/ndisc.h>
  #include <net/addrconf.h>
  #include <net/ip.h>
  #include <net/udp.h>
  #include <net/icmp.h>
  #include <net/ipip.h>
  #include <net/inet_ecn.h>
  #include <net/xfrm.h>
  #include <net/dsfield.h>
8190d9009   Pavel Emelyanov   [SIT]: Introduce ...
53
54
  #include <net/net_namespace.h>
  #include <net/netns/generic.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
55
56
57
58
59
60
61
62
  
  /*
     This version of net/ipv6/sit.c is cloned of net/ipv4/ip_gre.c
  
     For comments look at net/ipv4/ip_gre.c --ANK
   */
  
  #define HASH_SIZE  16
e69a4adc6   Al Viro   [IPV6]: Misc endi...
63
  #define HASH(addr) (((__force u32)addr^((__force u32)addr>>4))&0xF)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
64

15fc1f705   Eric Dumazet   sit: percpu stats...
65
  static int ipip6_tunnel_init(struct net_device *dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
66
  static void ipip6_tunnel_setup(struct net_device *dev);
15fc1f705   Eric Dumazet   sit: percpu stats...
67
  static void ipip6_dev_free(struct net_device *dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
68

f99189b18   Eric Dumazet   netns: net_identi...
69
  static int sit_net_id __read_mostly;
8190d9009   Pavel Emelyanov   [SIT]: Introduce ...
70
  struct sit_net {
3a43be3c3   Eric Dumazet   sit: get rid of i...
71
72
73
74
75
  	struct ip_tunnel __rcu *tunnels_r_l[HASH_SIZE];
  	struct ip_tunnel __rcu *tunnels_r[HASH_SIZE];
  	struct ip_tunnel __rcu *tunnels_l[HASH_SIZE];
  	struct ip_tunnel __rcu *tunnels_wc[1];
  	struct ip_tunnel __rcu **tunnels[4];
291821766   Pavel Emelyanov   [SIT]: Make tunne...
76

cd3dbc194   Pavel Emelyanov   [SIT]: Make the f...
77
  	struct net_device *fb_tunnel_dev;
8190d9009   Pavel Emelyanov   [SIT]: Introduce ...
78
  };
4543c10de   Eric Dumazet   ipv6 sit: RCU con...
79
  /*
3a43be3c3   Eric Dumazet   sit: get rid of i...
80
   * Locking : hash tables are protected by RCU and RTNL
4543c10de   Eric Dumazet   ipv6 sit: RCU con...
81
   */
4543c10de   Eric Dumazet   ipv6 sit: RCU con...
82
83
84
  
  #define for_each_ip_tunnel_rcu(start) \
  	for (t = rcu_dereference(start); t; t = rcu_dereference(t->next))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
85

15fc1f705   Eric Dumazet   sit: percpu stats...
86
87
88
89
90
91
  /* often modified stats are per cpu, other are shared (netdev->stats) */
  struct pcpu_tstats {
  	unsigned long	rx_packets;
  	unsigned long	rx_bytes;
  	unsigned long	tx_packets;
  	unsigned long	tx_bytes;
8ce120f11   Eric Dumazet   net: better pcpu ...
92
  } __attribute__((aligned(4*sizeof(unsigned long))));
15fc1f705   Eric Dumazet   sit: percpu stats...
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
  
  static struct net_device_stats *ipip6_get_stats(struct net_device *dev)
  {
  	struct pcpu_tstats sum = { 0 };
  	int i;
  
  	for_each_possible_cpu(i) {
  		const struct pcpu_tstats *tstats = per_cpu_ptr(dev->tstats, i);
  
  		sum.rx_packets += tstats->rx_packets;
  		sum.rx_bytes   += tstats->rx_bytes;
  		sum.tx_packets += tstats->tx_packets;
  		sum.tx_bytes   += tstats->tx_bytes;
  	}
  	dev->stats.rx_packets = sum.rx_packets;
  	dev->stats.rx_bytes   = sum.rx_bytes;
  	dev->stats.tx_packets = sum.tx_packets;
  	dev->stats.tx_bytes   = sum.tx_bytes;
  	return &dev->stats;
  }
4543c10de   Eric Dumazet   ipv6 sit: RCU con...
113
114
115
  /*
   * Must be invoked with rcu_read_lock
   */
ca8def148   Pavel Emelyanov   [SIT]: Add net/si...
116
  static struct ip_tunnel * ipip6_tunnel_lookup(struct net *net,
4fddbf5d7   Sascha Hlusiak   sit: strictly res...
117
  		struct net_device *dev, __be32 remote, __be32 local)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
118
  {
3a43be3c3   Eric Dumazet   sit: get rid of i...
119
120
  	unsigned int h0 = HASH(remote);
  	unsigned int h1 = HASH(local);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
121
  	struct ip_tunnel *t;
291821766   Pavel Emelyanov   [SIT]: Make tunne...
122
  	struct sit_net *sitn = net_generic(net, sit_net_id);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
123

4543c10de   Eric Dumazet   ipv6 sit: RCU con...
124
  	for_each_ip_tunnel_rcu(sitn->tunnels_r_l[h0 ^ h1]) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
125
  		if (local == t->parms.iph.saddr &&
4fddbf5d7   Sascha Hlusiak   sit: strictly res...
126
127
128
  		    remote == t->parms.iph.daddr &&
  		    (!dev || !t->parms.link || dev->iflink == t->parms.link) &&
  		    (t->dev->flags & IFF_UP))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
129
130
  			return t;
  	}
4543c10de   Eric Dumazet   ipv6 sit: RCU con...
131
  	for_each_ip_tunnel_rcu(sitn->tunnels_r[h0]) {
4fddbf5d7   Sascha Hlusiak   sit: strictly res...
132
133
134
  		if (remote == t->parms.iph.daddr &&
  		    (!dev || !t->parms.link || dev->iflink == t->parms.link) &&
  		    (t->dev->flags & IFF_UP))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
135
136
  			return t;
  	}
4543c10de   Eric Dumazet   ipv6 sit: RCU con...
137
  	for_each_ip_tunnel_rcu(sitn->tunnels_l[h1]) {
4fddbf5d7   Sascha Hlusiak   sit: strictly res...
138
139
140
  		if (local == t->parms.iph.saddr &&
  		    (!dev || !t->parms.link || dev->iflink == t->parms.link) &&
  		    (t->dev->flags & IFF_UP))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
141
142
  			return t;
  	}
4543c10de   Eric Dumazet   ipv6 sit: RCU con...
143
  	t = rcu_dereference(sitn->tunnels_wc[0]);
4fddbf5d7   Sascha Hlusiak   sit: strictly res...
144
  	if ((t != NULL) && (t->dev->flags & IFF_UP))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
145
146
147
  		return t;
  	return NULL;
  }
3a43be3c3   Eric Dumazet   sit: get rid of i...
148
  static struct ip_tunnel __rcu **__ipip6_bucket(struct sit_net *sitn,
ca8def148   Pavel Emelyanov   [SIT]: Add net/si...
149
  		struct ip_tunnel_parm *parms)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
150
  {
420fe234a   YOSHIFUJI Hideaki   [IPV6] SIT: Unify...
151
152
  	__be32 remote = parms->iph.daddr;
  	__be32 local = parms->iph.saddr;
3a43be3c3   Eric Dumazet   sit: get rid of i...
153
  	unsigned int h = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
154
155
156
157
158
159
160
161
162
163
  	int prio = 0;
  
  	if (remote) {
  		prio |= 2;
  		h ^= HASH(remote);
  	}
  	if (local) {
  		prio |= 1;
  		h ^= HASH(local);
  	}
291821766   Pavel Emelyanov   [SIT]: Make tunne...
164
  	return &sitn->tunnels[prio][h];
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
165
  }
3a43be3c3   Eric Dumazet   sit: get rid of i...
166
  static inline struct ip_tunnel __rcu **ipip6_bucket(struct sit_net *sitn,
ca8def148   Pavel Emelyanov   [SIT]: Add net/si...
167
  		struct ip_tunnel *t)
420fe234a   YOSHIFUJI Hideaki   [IPV6] SIT: Unify...
168
  {
ca8def148   Pavel Emelyanov   [SIT]: Add net/si...
169
  	return __ipip6_bucket(sitn, &t->parms);
420fe234a   YOSHIFUJI Hideaki   [IPV6] SIT: Unify...
170
  }
ca8def148   Pavel Emelyanov   [SIT]: Add net/si...
171
  static void ipip6_tunnel_unlink(struct sit_net *sitn, struct ip_tunnel *t)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
172
  {
3a43be3c3   Eric Dumazet   sit: get rid of i...
173
174
175
176
177
178
179
  	struct ip_tunnel __rcu **tp;
  	struct ip_tunnel *iter;
  
  	for (tp = ipip6_bucket(sitn, t);
  	     (iter = rtnl_dereference(*tp)) != NULL;
  	     tp = &iter->next) {
  		if (t == iter) {
cf778b00e   Eric Dumazet   net: reintroduce ...
180
  			rcu_assign_pointer(*tp, t->next);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
181
182
183
184
  			break;
  		}
  	}
  }
ca8def148   Pavel Emelyanov   [SIT]: Add net/si...
185
  static void ipip6_tunnel_link(struct sit_net *sitn, struct ip_tunnel *t)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
186
  {
3a43be3c3   Eric Dumazet   sit: get rid of i...
187
  	struct ip_tunnel __rcu **tp = ipip6_bucket(sitn, t);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
188

cf778b00e   Eric Dumazet   net: reintroduce ...
189
190
  	rcu_assign_pointer(t->next, rtnl_dereference(*tp));
  	rcu_assign_pointer(*tp, t);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
191
  }
e0c939481   YOSHIFUJI Hideaki / 吉藤英明   ipv6 sit: Ensure ...
192
  static void ipip6_tunnel_clone_6rd(struct net_device *dev, struct sit_net *sitn)
fa857afcf   YOSHIFUJI Hideaki / 吉藤英明   ipv6 sit: 6rd (IP...
193
194
  {
  #ifdef CONFIG_IPV6_SIT_6RD
e0c939481   YOSHIFUJI Hideaki / 吉藤英明   ipv6 sit: Ensure ...
195
  	struct ip_tunnel *t = netdev_priv(dev);
fa857afcf   YOSHIFUJI Hideaki / 吉藤英明   ipv6 sit: 6rd (IP...
196
197
198
199
200
201
202
203
204
205
206
  	if (t->dev == sitn->fb_tunnel_dev) {
  		ipv6_addr_set(&t->ip6rd.prefix, htonl(0x20020000), 0, 0, 0);
  		t->ip6rd.relay_prefix = 0;
  		t->ip6rd.prefixlen = 16;
  		t->ip6rd.relay_prefixlen = 0;
  	} else {
  		struct ip_tunnel *t0 = netdev_priv(sitn->fb_tunnel_dev);
  		memcpy(&t->ip6rd, &t0->ip6rd, sizeof(t->ip6rd));
  	}
  #endif
  }
3a43be3c3   Eric Dumazet   sit: get rid of i...
207
  static struct ip_tunnel *ipip6_tunnel_locate(struct net *net,
ca8def148   Pavel Emelyanov   [SIT]: Add net/si...
208
  		struct ip_tunnel_parm *parms, int create)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
209
  {
e69a4adc6   Al Viro   [IPV6]: Misc endi...
210
211
  	__be32 remote = parms->iph.daddr;
  	__be32 local = parms->iph.saddr;
3a43be3c3   Eric Dumazet   sit: get rid of i...
212
213
  	struct ip_tunnel *t, *nt;
  	struct ip_tunnel __rcu **tp;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
214
  	struct net_device *dev;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
215
  	char name[IFNAMSIZ];
ca8def148   Pavel Emelyanov   [SIT]: Add net/si...
216
  	struct sit_net *sitn = net_generic(net, sit_net_id);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
217

3a43be3c3   Eric Dumazet   sit: get rid of i...
218
219
220
  	for (tp = __ipip6_bucket(sitn, parms);
  	    (t = rtnl_dereference(*tp)) != NULL;
  	     tp = &t->next) {
8db99e571   Sascha Hlusiak   sit: Fail to crea...
221
  		if (local == t->parms.iph.saddr &&
4fddbf5d7   Sascha Hlusiak   sit: strictly res...
222
223
  		    remote == t->parms.iph.daddr &&
  		    parms->link == t->parms.link) {
8db99e571   Sascha Hlusiak   sit: Fail to crea...
224
225
226
227
228
  			if (create)
  				return NULL;
  			else
  				return t;
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
229
230
231
232
233
234
  	}
  	if (!create)
  		goto failed;
  
  	if (parms->name[0])
  		strlcpy(name, parms->name, IFNAMSIZ);
34cc7ba63   Pavel Emelyanov   [IP_TUNNEL]: Don'...
235
  	else
15fc1f705   Eric Dumazet   sit: percpu stats...
236
  		strcpy(name, "sit%d");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
237
238
239
240
  
  	dev = alloc_netdev(sizeof(*t), name, ipip6_tunnel_setup);
  	if (dev == NULL)
  		return NULL;
7a97146cc   Pavel Emelyanov   [SIT]: Allow to c...
241
  	dev_net_set(dev, net);
2941a4863   Patrick McHardy   [NET]: Convert ne...
242
  	nt = netdev_priv(dev);
1326c3d5a   Stephen Hemminger   ipv6: convert tun...
243

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
244
  	nt->parms = *parms;
15fc1f705   Eric Dumazet   sit: percpu stats...
245
246
  	if (ipip6_tunnel_init(dev) < 0)
  		goto failed_free;
e0c939481   YOSHIFUJI Hideaki / 吉藤英明   ipv6 sit: Ensure ...
247
  	ipip6_tunnel_clone_6rd(dev, sitn);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
248

c7dc89c0a   Fred L. Templin   [IPV6]: Add RFC42...
249
250
  	if (parms->i_flags & SIT_ISATAP)
  		dev->priv_flags |= IFF_ISATAP;
b37d428b2   Pavel Emelyanov   [INET]: Don't cre...
251
252
  	if (register_netdevice(dev) < 0)
  		goto failed_free;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
253

72b36015b   Ted Feng   ipip, sit: copy p...
254
  	strcpy(nt->parms.name, dev->name);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
255
  	dev_hold(dev);
ca8def148   Pavel Emelyanov   [SIT]: Add net/si...
256
  	ipip6_tunnel_link(sitn, nt);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
257
  	return nt;
b37d428b2   Pavel Emelyanov   [INET]: Don't cre...
258
  failed_free:
15fc1f705   Eric Dumazet   sit: percpu stats...
259
  	ipip6_dev_free(dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
260
261
262
  failed:
  	return NULL;
  }
ef9a9d118   Eric Dumazet   ipv6 sit: RCU con...
263
264
265
266
  #define for_each_prl_rcu(start)			\
  	for (prl = rcu_dereference(start);	\
  	     prl;				\
  	     prl = rcu_dereference(prl->next))
fadf6bf06   Templin, Fred L   [IPV6] SIT: Add P...
267
  static struct ip_tunnel_prl_entry *
3fcfa1290   YOSHIFUJI Hideaki   [IPV6] SIT: Fix l...
268
  __ipip6_tunnel_locate_prl(struct ip_tunnel *t, __be32 addr)
fadf6bf06   Templin, Fred L   [IPV6] SIT: Add P...
269
  {
ef9a9d118   Eric Dumazet   ipv6 sit: RCU con...
270
  	struct ip_tunnel_prl_entry *prl;
fadf6bf06   Templin, Fred L   [IPV6] SIT: Add P...
271

ef9a9d118   Eric Dumazet   ipv6 sit: RCU con...
272
273
  	for_each_prl_rcu(t->prl)
  		if (prl->addr == addr)
fadf6bf06   Templin, Fred L   [IPV6] SIT: Add P...
274
  			break;
ef9a9d118   Eric Dumazet   ipv6 sit: RCU con...
275
  	return prl;
fadf6bf06   Templin, Fred L   [IPV6] SIT: Add P...
276
277
  
  }
2b4743bd6   YOSHIFUJI Hideaki   ipv6 sit: Avoid e...
278
279
  static int ipip6_tunnel_get_prl(struct ip_tunnel *t,
  				struct ip_tunnel_prl __user *a)
300aaeeaa   YOSHIFUJI Hideaki   [IPV6] SIT: Add S...
280
  {
2b4743bd6   YOSHIFUJI Hideaki   ipv6 sit: Avoid e...
281
  	struct ip_tunnel_prl kprl, *kp;
300aaeeaa   YOSHIFUJI Hideaki   [IPV6] SIT: Add S...
282
283
284
  	struct ip_tunnel_prl_entry *prl;
  	unsigned int cmax, c = 0, ca, len;
  	int ret = 0;
2b4743bd6   YOSHIFUJI Hideaki   ipv6 sit: Avoid e...
285
286
287
288
  	if (copy_from_user(&kprl, a, sizeof(kprl)))
  		return -EFAULT;
  	cmax = kprl.datalen / sizeof(kprl);
  	if (cmax > 1 && kprl.addr != htonl(INADDR_ANY))
300aaeeaa   YOSHIFUJI Hideaki   [IPV6] SIT: Add S...
289
290
291
292
293
294
295
296
  		cmax = 1;
  
  	/* For simple GET or for root users,
  	 * we try harder to allocate.
  	 */
  	kp = (cmax <= 1 || capable(CAP_NET_ADMIN)) ?
  		kcalloc(cmax, sizeof(*kp), GFP_KERNEL) :
  		NULL;
ef9a9d118   Eric Dumazet   ipv6 sit: RCU con...
297
  	rcu_read_lock();
300aaeeaa   YOSHIFUJI Hideaki   [IPV6] SIT: Add S...
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
  
  	ca = t->prl_count < cmax ? t->prl_count : cmax;
  
  	if (!kp) {
  		/* We don't try hard to allocate much memory for
  		 * non-root users.
  		 * For root users, retry allocating enough memory for
  		 * the answer.
  		 */
  		kp = kcalloc(ca, sizeof(*kp), GFP_ATOMIC);
  		if (!kp) {
  			ret = -ENOMEM;
  			goto out;
  		}
  	}
  
  	c = 0;
ef9a9d118   Eric Dumazet   ipv6 sit: RCU con...
315
  	for_each_prl_rcu(t->prl) {
298bf12dd   Sascha Hlusiak   sit: fix off-by-o...
316
  		if (c >= cmax)
300aaeeaa   YOSHIFUJI Hideaki   [IPV6] SIT: Add S...
317
  			break;
2b4743bd6   YOSHIFUJI Hideaki   ipv6 sit: Avoid e...
318
  		if (kprl.addr != htonl(INADDR_ANY) && prl->addr != kprl.addr)
300aaeeaa   YOSHIFUJI Hideaki   [IPV6] SIT: Add S...
319
320
321
322
  			continue;
  		kp[c].addr = prl->addr;
  		kp[c].flags = prl->flags;
  		c++;
2b4743bd6   YOSHIFUJI Hideaki   ipv6 sit: Avoid e...
323
  		if (kprl.addr != htonl(INADDR_ANY))
300aaeeaa   YOSHIFUJI Hideaki   [IPV6] SIT: Add S...
324
325
326
  			break;
  	}
  out:
ef9a9d118   Eric Dumazet   ipv6 sit: RCU con...
327
  	rcu_read_unlock();
300aaeeaa   YOSHIFUJI Hideaki   [IPV6] SIT: Add S...
328
329
  
  	len = sizeof(*kp) * c;
2b4743bd6   YOSHIFUJI Hideaki   ipv6 sit: Avoid e...
330
331
332
  	ret = 0;
  	if ((len && copy_to_user(a + 1, kp, len)) || put_user(len, &a->datalen))
  		ret = -EFAULT;
300aaeeaa   YOSHIFUJI Hideaki   [IPV6] SIT: Add S...
333
334
  
  	kfree(kp);
300aaeeaa   YOSHIFUJI Hideaki   [IPV6] SIT: Add S...
335

2b4743bd6   YOSHIFUJI Hideaki   ipv6 sit: Avoid e...
336
  	return ret;
300aaeeaa   YOSHIFUJI Hideaki   [IPV6] SIT: Add S...
337
  }
fadf6bf06   Templin, Fred L   [IPV6] SIT: Add P...
338
339
340
341
  static int
  ipip6_tunnel_add_prl(struct ip_tunnel *t, struct ip_tunnel_prl *a, int chg)
  {
  	struct ip_tunnel_prl_entry *p;
3fcfa1290   YOSHIFUJI Hideaki   [IPV6] SIT: Fix l...
342
  	int err = 0;
0009ae1f5   YOSHIFUJI Hideaki   [IPV6] SIT: Disal...
343
344
  	if (a->addr == htonl(INADDR_ANY))
  		return -EINVAL;
aac4dddc3   Eric Dumazet   ipv6: get rid of ...
345
  	ASSERT_RTNL();
fadf6bf06   Templin, Fred L   [IPV6] SIT: Add P...
346

3a43be3c3   Eric Dumazet   sit: get rid of i...
347
  	for (p = rtnl_dereference(t->prl); p; p = rtnl_dereference(p->next)) {
300aaeeaa   YOSHIFUJI Hideaki   [IPV6] SIT: Add S...
348
  		if (p->addr == a->addr) {
ef9a9d118   Eric Dumazet   ipv6 sit: RCU con...
349
350
351
352
  			if (chg) {
  				p->flags = a->flags;
  				goto out;
  			}
3fcfa1290   YOSHIFUJI Hideaki   [IPV6] SIT: Fix l...
353
354
  			err = -EEXIST;
  			goto out;
fadf6bf06   Templin, Fred L   [IPV6] SIT: Add P...
355
356
  		}
  	}
3fcfa1290   YOSHIFUJI Hideaki   [IPV6] SIT: Fix l...
357
358
359
360
  	if (chg) {
  		err = -ENXIO;
  		goto out;
  	}
fadf6bf06   Templin, Fred L   [IPV6] SIT: Add P...
361
362
  
  	p = kzalloc(sizeof(struct ip_tunnel_prl_entry), GFP_KERNEL);
3fcfa1290   YOSHIFUJI Hideaki   [IPV6] SIT: Fix l...
363
364
365
366
  	if (!p) {
  		err = -ENOBUFS;
  		goto out;
  	}
fadf6bf06   Templin, Fred L   [IPV6] SIT: Add P...
367

fadf6bf06   Templin, Fred L   [IPV6] SIT: Add P...
368
  	p->next = t->prl;
300aaeeaa   YOSHIFUJI Hideaki   [IPV6] SIT: Add S...
369
370
  	p->addr = a->addr;
  	p->flags = a->flags;
ef9a9d118   Eric Dumazet   ipv6 sit: RCU con...
371
  	t->prl_count++;
cf778b00e   Eric Dumazet   net: reintroduce ...
372
  	rcu_assign_pointer(t->prl, p);
3fcfa1290   YOSHIFUJI Hideaki   [IPV6] SIT: Fix l...
373
  out:
3fcfa1290   YOSHIFUJI Hideaki   [IPV6] SIT: Fix l...
374
  	return err;
fadf6bf06   Templin, Fred L   [IPV6] SIT: Add P...
375
  }
ef9a9d118   Eric Dumazet   ipv6 sit: RCU con...
376
377
378
379
380
381
  static void prl_list_destroy_rcu(struct rcu_head *head)
  {
  	struct ip_tunnel_prl_entry *p, *n;
  
  	p = container_of(head, struct ip_tunnel_prl_entry, rcu_head);
  	do {
753ea8e96   Eric Dumazet   net: ipv6: sit: f...
382
  		n = rcu_dereference_protected(p->next, 1);
ef9a9d118   Eric Dumazet   ipv6 sit: RCU con...
383
384
385
386
  		kfree(p);
  		p = n;
  	} while (p);
  }
fadf6bf06   Templin, Fred L   [IPV6] SIT: Add P...
387
388
389
  static int
  ipip6_tunnel_del_prl(struct ip_tunnel *t, struct ip_tunnel_prl *a)
  {
753ea8e96   Eric Dumazet   net: ipv6: sit: f...
390
391
  	struct ip_tunnel_prl_entry *x;
  	struct ip_tunnel_prl_entry __rcu **p;
3fcfa1290   YOSHIFUJI Hideaki   [IPV6] SIT: Fix l...
392
  	int err = 0;
aac4dddc3   Eric Dumazet   ipv6: get rid of ...
393
  	ASSERT_RTNL();
fadf6bf06   Templin, Fred L   [IPV6] SIT: Add P...
394

0009ae1f5   YOSHIFUJI Hideaki   [IPV6] SIT: Disal...
395
  	if (a && a->addr != htonl(INADDR_ANY)) {
753ea8e96   Eric Dumazet   net: ipv6: sit: f...
396
397
398
399
  		for (p = &t->prl;
  		     (x = rtnl_dereference(*p)) != NULL;
  		     p = &x->next) {
  			if (x->addr == a->addr) {
fadf6bf06   Templin, Fred L   [IPV6] SIT: Add P...
400
  				*p = x->next;
11c476f31   Paul E. McKenney   net,rcu: convert ...
401
  				kfree_rcu(x, rcu_head);
300aaeeaa   YOSHIFUJI Hideaki   [IPV6] SIT: Add S...
402
  				t->prl_count--;
3fcfa1290   YOSHIFUJI Hideaki   [IPV6] SIT: Fix l...
403
  				goto out;
fadf6bf06   Templin, Fred L   [IPV6] SIT: Add P...
404
405
  			}
  		}
3fcfa1290   YOSHIFUJI Hideaki   [IPV6] SIT: Fix l...
406
  		err = -ENXIO;
fadf6bf06   Templin, Fred L   [IPV6] SIT: Add P...
407
  	} else {
753ea8e96   Eric Dumazet   net: ipv6: sit: f...
408
409
  		x = rtnl_dereference(t->prl);
  		if (x) {
ef9a9d118   Eric Dumazet   ipv6 sit: RCU con...
410
  			t->prl_count = 0;
ef9a9d118   Eric Dumazet   ipv6 sit: RCU con...
411
412
  			call_rcu(&x->rcu_head, prl_list_destroy_rcu);
  			t->prl = NULL;
fadf6bf06   Templin, Fred L   [IPV6] SIT: Add P...
413
414
  		}
  	}
3fcfa1290   YOSHIFUJI Hideaki   [IPV6] SIT: Fix l...
415
  out:
4b2796017   Sascha Hlusiak   sit: ipip6_tunnel...
416
  	return err;
fadf6bf06   Templin, Fred L   [IPV6] SIT: Add P...
417
  }
fadf6bf06   Templin, Fred L   [IPV6] SIT: Add P...
418
  static int
b71d1d426   Eric Dumazet   inet: constify ip...
419
  isatap_chksrc(struct sk_buff *skb, const struct iphdr *iph, struct ip_tunnel *t)
fadf6bf06   Templin, Fred L   [IPV6] SIT: Add P...
420
  {
3fcfa1290   YOSHIFUJI Hideaki   [IPV6] SIT: Fix l...
421
  	struct ip_tunnel_prl_entry *p;
fadf6bf06   Templin, Fred L   [IPV6] SIT: Add P...
422
  	int ok = 1;
ef9a9d118   Eric Dumazet   ipv6 sit: RCU con...
423
  	rcu_read_lock();
3fcfa1290   YOSHIFUJI Hideaki   [IPV6] SIT: Fix l...
424
  	p = __ipip6_tunnel_locate_prl(t, iph->saddr);
fadf6bf06   Templin, Fred L   [IPV6] SIT: Add P...
425
  	if (p) {
300aaeeaa   YOSHIFUJI Hideaki   [IPV6] SIT: Add S...
426
  		if (p->flags & PRL_DEFAULT)
fadf6bf06   Templin, Fred L   [IPV6] SIT: Add P...
427
428
429
430
  			skb->ndisc_nodetype = NDISC_NODETYPE_DEFAULT;
  		else
  			skb->ndisc_nodetype = NDISC_NODETYPE_NODEFAULT;
  	} else {
b71d1d426   Eric Dumazet   inet: constify ip...
431
  		const struct in6_addr *addr6 = &ipv6_hdr(skb)->saddr;
fadf6bf06   Templin, Fred L   [IPV6] SIT: Add P...
432
433
  		if (ipv6_addr_is_isatap(addr6) &&
  		    (addr6->s6_addr32[3] == iph->saddr) &&
52eeeb848   YOSHIFUJI Hideaki   [IPV6]: Unify ip6...
434
  		    ipv6_chk_prefix(addr6, t->dev))
fadf6bf06   Templin, Fred L   [IPV6] SIT: Add P...
435
436
437
438
  			skb->ndisc_nodetype = NDISC_NODETYPE_HOST;
  		else
  			ok = 0;
  	}
ef9a9d118   Eric Dumazet   ipv6 sit: RCU con...
439
  	rcu_read_unlock();
fadf6bf06   Templin, Fred L   [IPV6] SIT: Add P...
440
441
  	return ok;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
442
443
  static void ipip6_tunnel_uninit(struct net_device *dev)
  {
ca8def148   Pavel Emelyanov   [SIT]: Add net/si...
444
445
  	struct net *net = dev_net(dev);
  	struct sit_net *sitn = net_generic(net, sit_net_id);
cd3dbc194   Pavel Emelyanov   [SIT]: Make the f...
446
  	if (dev == sitn->fb_tunnel_dev) {
a9b3cd7f3   Stephen Hemminger   rcu: convert uses...
447
  		RCU_INIT_POINTER(sitn->tunnels_wc[0], NULL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
448
  	} else {
ca8def148   Pavel Emelyanov   [SIT]: Add net/si...
449
  		ipip6_tunnel_unlink(sitn, netdev_priv(dev));
02e10b90c   YOSHIFUJI Hideaki   [IPV6] SIT: Spars...
450
  		ipip6_tunnel_del_prl(netdev_priv(dev), NULL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
451
  	}
3a43be3c3   Eric Dumazet   sit: get rid of i...
452
  	dev_put(dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
453
  }
c73cb5a2d   Kazunori MIYAZAWA   [IPSEC]: make sit...
454
  static int ipip6_err(struct sk_buff *skb, u32 info)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
455
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
456

071f92d05   Rami Rosen   net: The world is...
457
  /* All the routers (except for Linux) return only
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
458
459
460
     8 bytes of packet payload. It means, that precise relaying of
     ICMP in the real Internet is absolutely infeasible.
   */
b71d1d426   Eric Dumazet   inet: constify ip...
461
  	const struct iphdr *iph = (const struct iphdr *)skb->data;
88c7664f1   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
462
463
  	const int type = icmp_hdr(skb)->type;
  	const int code = icmp_hdr(skb)->code;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
464
  	struct ip_tunnel *t;
c73cb5a2d   Kazunori MIYAZAWA   [IPSEC]: make sit...
465
  	int err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
466
467
468
469
  
  	switch (type) {
  	default:
  	case ICMP_PARAMETERPROB:
c73cb5a2d   Kazunori MIYAZAWA   [IPSEC]: make sit...
470
  		return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
471
472
473
474
475
476
  
  	case ICMP_DEST_UNREACH:
  		switch (code) {
  		case ICMP_SR_FAILED:
  		case ICMP_PORT_UNREACH:
  			/* Impossible event. */
c73cb5a2d   Kazunori MIYAZAWA   [IPSEC]: make sit...
477
  			return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
478
479
  		case ICMP_FRAG_NEEDED:
  			/* Soft state for pmtu is maintained by IP core. */
c73cb5a2d   Kazunori MIYAZAWA   [IPSEC]: make sit...
480
  			return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
481
482
483
484
485
486
487
488
489
490
  		default:
  			/* All others are translated to HOST_UNREACH.
  			   rfc2003 contains "deep thoughts" about NET_UNREACH,
  			   I believe they are just ether pollution. --ANK
  			 */
  			break;
  		}
  		break;
  	case ICMP_TIME_EXCEEDED:
  		if (code != ICMP_EXC_TTL)
c73cb5a2d   Kazunori MIYAZAWA   [IPSEC]: make sit...
491
  			return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
492
493
  		break;
  	}
c73cb5a2d   Kazunori MIYAZAWA   [IPSEC]: make sit...
494
  	err = -ENOENT;
4543c10de   Eric Dumazet   ipv6 sit: RCU con...
495
  	rcu_read_lock();
4fddbf5d7   Sascha Hlusiak   sit: strictly res...
496
497
498
499
  	t = ipip6_tunnel_lookup(dev_net(skb->dev),
  				skb->dev,
  				iph->daddr,
  				iph->saddr);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
500
501
  	if (t == NULL || t->parms.iph.daddr == 0)
  		goto out;
c73cb5a2d   Kazunori MIYAZAWA   [IPSEC]: make sit...
502
503
  
  	err = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
504
505
  	if (t->parms.iph.ttl == 0 && type == ICMP_TIME_EXCEEDED)
  		goto out;
bb80087a9   Wei Yongjun   sit: used time_be...
506
  	if (time_before(jiffies, t->err_time + IPTUNNEL_ERR_TIMEO))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
507
508
509
510
511
  		t->err_count++;
  	else
  		t->err_count = 1;
  	t->err_time = jiffies;
  out:
4543c10de   Eric Dumazet   ipv6 sit: RCU con...
512
  	rcu_read_unlock();
c73cb5a2d   Kazunori MIYAZAWA   [IPSEC]: make sit...
513
  	return err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
514
  }
b71d1d426   Eric Dumazet   inet: constify ip...
515
  static inline void ipip6_ecn_decapsulate(const struct iphdr *iph, struct sk_buff *skb)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
516
517
  {
  	if (INET_ECN_is_ce(iph->tos))
0660e03f6   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
518
  		IP6_ECN_set_ce(ipv6_hdr(skb));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
519
520
521
522
  }
  
  static int ipip6_rcv(struct sk_buff *skb)
  {
b71d1d426   Eric Dumazet   inet: constify ip...
523
  	const struct iphdr *iph;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
524
525
526
527
  	struct ip_tunnel *tunnel;
  
  	if (!pskb_may_pull(skb, sizeof(struct ipv6hdr)))
  		goto out;
eddc9ec53   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
528
  	iph = ip_hdr(skb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
529

4543c10de   Eric Dumazet   ipv6 sit: RCU con...
530
  	rcu_read_lock();
4fddbf5d7   Sascha Hlusiak   sit: strictly res...
531
532
533
  	tunnel = ipip6_tunnel_lookup(dev_net(skb->dev), skb->dev,
  				     iph->saddr, iph->daddr);
  	if (tunnel != NULL) {
15fc1f705   Eric Dumazet   sit: percpu stats...
534
  		struct pcpu_tstats *tstats;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
535
  		secpath_reset(skb);
b0e380b1d   Arnaldo Carvalho de Melo   [SK_BUFF]: unions...
536
  		skb->mac_header = skb->network_header;
c1d2bbe1c   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
537
  		skb_reset_network_header(skb);
8cdfab8a4   Patrick McHardy   [IPV4]: reset IPC...
538
  		IPCB(skb)->flags = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
539
540
  		skb->protocol = htons(ETH_P_IPV6);
  		skb->pkt_type = PACKET_HOST;
c7dc89c0a   Fred L. Templin   [IPV6]: Add RFC42...
541
542
  
  		if ((tunnel->dev->priv_flags & IFF_ISATAP) &&
fadf6bf06   Templin, Fred L   [IPV6] SIT: Add P...
543
  		    !isatap_chksrc(skb, iph, tunnel)) {
4eecc107a   Pavel Emelyanov   sit: Use on-devic...
544
  			tunnel->dev->stats.rx_errors++;
4543c10de   Eric Dumazet   ipv6 sit: RCU con...
545
  			rcu_read_unlock();
c7dc89c0a   Fred L. Templin   [IPV6]: Add RFC42...
546
547
548
  			kfree_skb(skb);
  			return 0;
  		}
d19d56ddc   Eric Dumazet   net: Introduce sk...
549

15fc1f705   Eric Dumazet   sit: percpu stats...
550
551
552
553
554
  		tstats = this_cpu_ptr(tunnel->dev->tstats);
  		tstats->rx_packets++;
  		tstats->rx_bytes += skb->len;
  
  		__skb_tunnel_rx(skb, tunnel->dev);
d19d56ddc   Eric Dumazet   net: Introduce sk...
555

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
556
  		ipip6_ecn_decapsulate(iph, skb);
8990f468a   Eric Dumazet   net: rx_dropped a...
557

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

4543c10de   Eric Dumazet   ipv6 sit: RCU con...
560
  		rcu_read_unlock();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
561
562
  		return 0;
  	}
6dcdd1b36   David McCullough   net/ipv6/sit.c: r...
563
  	/* no tunnel matched,  let upstream know, ipsec may handle it */
4543c10de   Eric Dumazet   ipv6 sit: RCU con...
564
  	rcu_read_unlock();
6dcdd1b36   David McCullough   net/ipv6/sit.c: r...
565
  	return 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
566
  out:
36ca34cc3   David S. Miller   sit: Add missing ...
567
  	kfree_skb(skb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
568
569
  	return 0;
  }
fa857afcf   YOSHIFUJI Hideaki / 吉藤英明   ipv6 sit: 6rd (IP...
570
571
572
573
574
  /*
   * Returns the embedded IPv4 address if the IPv6 address
   * comes from 6rd / 6to4 (RFC 3056) addr space.
   */
  static inline
b71d1d426   Eric Dumazet   inet: constify ip...
575
  __be32 try_6rd(const struct in6_addr *v6dst, struct ip_tunnel *tunnel)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
576
  {
e69a4adc6   Al Viro   [IPV6]: Misc endi...
577
  	__be32 dst = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
578

fa857afcf   YOSHIFUJI Hideaki / 吉藤英明   ipv6 sit: 6rd (IP...
579
580
581
  #ifdef CONFIG_IPV6_SIT_6RD
  	if (ipv6_prefix_equal(v6dst, &tunnel->ip6rd.prefix,
  			      tunnel->ip6rd.prefixlen)) {
3a43be3c3   Eric Dumazet   sit: get rid of i...
582
  		unsigned int pbw0, pbi0;
fa857afcf   YOSHIFUJI Hideaki / 吉藤英明   ipv6 sit: 6rd (IP...
583
584
585
586
587
  		int pbi1;
  		u32 d;
  
  		pbw0 = tunnel->ip6rd.prefixlen >> 5;
  		pbi0 = tunnel->ip6rd.prefixlen & 0x1f;
e7db38c38   YOSHIFUJI Hideaki / 吉藤英明   ipv6 sit: Fix 6rd...
588
  		d = (ntohl(v6dst->s6_addr32[pbw0]) << pbi0) >>
fa857afcf   YOSHIFUJI Hideaki / 吉藤英明   ipv6 sit: 6rd (IP...
589
590
591
592
  		    tunnel->ip6rd.relay_prefixlen;
  
  		pbi1 = pbi0 - tunnel->ip6rd.relay_prefixlen;
  		if (pbi1 > 0)
e7db38c38   YOSHIFUJI Hideaki / 吉藤英明   ipv6 sit: Fix 6rd...
593
  			d |= ntohl(v6dst->s6_addr32[pbw0 + 1]) >>
fa857afcf   YOSHIFUJI Hideaki / 吉藤英明   ipv6 sit: 6rd (IP...
594
595
596
597
598
  			     (32 - pbi1);
  
  		dst = tunnel->ip6rd.relay_prefix | htonl(d);
  	}
  #else
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
599
  	if (v6dst->s6_addr16[0] == htons(0x2002)) {
1ab1457c4   YOSHIFUJI Hideaki   [NET] IPV6: Fix w...
600
  		/* 6to4 v6 addr has 16 bits prefix, 32 v4addr, 16 SLA, ... */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
601
602
  		memcpy(&dst, &v6dst->s6_addr16[1], 4);
  	}
fa857afcf   YOSHIFUJI Hideaki / 吉藤英明   ipv6 sit: 6rd (IP...
603
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
604
605
606
607
608
609
610
  	return dst;
  }
  
  /*
   *	This function assumes it is being called from dev_queue_xmit()
   *	and that skb is filled properly by that function.
   */
6fef4c0c8   Stephen Hemminger   netdev: convert p...
611
612
  static netdev_tx_t ipip6_tunnel_xmit(struct sk_buff *skb,
  				     struct net_device *dev)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
613
  {
2941a4863   Patrick McHardy   [NET]: Convert ne...
614
  	struct ip_tunnel *tunnel = netdev_priv(dev);
15fc1f705   Eric Dumazet   sit: percpu stats...
615
  	struct pcpu_tstats *tstats;
b71d1d426   Eric Dumazet   inet: constify ip...
616
617
  	const struct iphdr  *tiph = &tunnel->parms.iph;
  	const struct ipv6hdr *iph6 = ipv6_hdr(skb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
618
  	u8     tos = tunnel->parms.iph.tos;
292f4f3ce   Herbert Xu   sit: Clean up DF ...
619
  	__be16 df = tiph->frag_off;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
620
  	struct rtable *rt;     			/* Route to the other host */
15fc1f705   Eric Dumazet   sit: percpu stats...
621
  	struct net_device *tdev;		/* Device to other host */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
622
  	struct iphdr  *iph;			/* Our new IP header */
c2636b4d9   Chuck Lever   [NET]: Treat the ...
623
  	unsigned int max_headroom;		/* The extra header space needed */
e69a4adc6   Al Viro   [IPV6]: Misc endi...
624
  	__be32 dst = tiph->daddr;
31e4543db   David S. Miller   ipv4: Make caller...
625
  	struct flowi4 fl4;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
626
  	int    mtu;
b71d1d426   Eric Dumazet   inet: constify ip...
627
  	const struct in6_addr *addr6;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
628
  	int addr_type;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
629
630
  	if (skb->protocol != htons(ETH_P_IPV6))
  		goto tx_error;
c2bceb3d7   Lionel Elie Mamane   sit tunnels: prop...
631
632
  	if (tos == 1)
  		tos = ipv6_get_dsfield(iph6);
c7dc89c0a   Fred L. Templin   [IPV6]: Add RFC42...
633
634
635
  	/* ISATAP (RFC4214) - must come before 6to4 */
  	if (dev->priv_flags & IFF_ISATAP) {
  		struct neighbour *neigh = NULL;
adf30907d   Eric Dumazet   net: skb->dst acc...
636
  		if (skb_dst(skb))
272174550   David Miller   net: Rename dst_g...
637
  			neigh = dst_get_neighbour_noref(skb_dst(skb));
c7dc89c0a   Fred L. Templin   [IPV6]: Add RFC42...
638
639
640
641
642
643
644
  
  		if (neigh == NULL) {
  			if (net_ratelimit())
  				printk(KERN_DEBUG "sit: nexthop == NULL
  ");
  			goto tx_error;
  		}
b71d1d426   Eric Dumazet   inet: constify ip...
645
  		addr6 = (const struct in6_addr*)&neigh->primary_key;
c7dc89c0a   Fred L. Templin   [IPV6]: Add RFC42...
646
647
648
649
650
651
652
653
  		addr_type = ipv6_addr_type(addr6);
  
  		if ((addr_type & IPV6_ADDR_UNICAST) &&
  		     ipv6_addr_is_isatap(addr6))
  			dst = addr6->s6_addr32[3];
  		else
  			goto tx_error;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
654
  	if (!dst)
fa857afcf   YOSHIFUJI Hideaki / 吉藤英明   ipv6 sit: 6rd (IP...
655
  		dst = try_6rd(&iph6->daddr, tunnel);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
656
657
658
  
  	if (!dst) {
  		struct neighbour *neigh = NULL;
adf30907d   Eric Dumazet   net: skb->dst acc...
659
  		if (skb_dst(skb))
272174550   David Miller   net: Rename dst_g...
660
  			neigh = dst_get_neighbour_noref(skb_dst(skb));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
661
662
663
664
665
666
667
  
  		if (neigh == NULL) {
  			if (net_ratelimit())
  				printk(KERN_DEBUG "sit: nexthop == NULL
  ");
  			goto tx_error;
  		}
b71d1d426   Eric Dumazet   inet: constify ip...
668
  		addr6 = (const struct in6_addr*)&neigh->primary_key;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
669
670
671
  		addr_type = ipv6_addr_type(addr6);
  
  		if (addr_type == IPV6_ADDR_ANY) {
0660e03f6   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
672
  			addr6 = &ipv6_hdr(skb)->daddr;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
673
674
675
676
677
678
679
680
  			addr_type = ipv6_addr_type(addr6);
  		}
  
  		if ((addr_type & IPV6_ADDR_COMPATv4) == 0)
  			goto tx_error_icmp;
  
  		dst = addr6->s6_addr32[3];
  	}
31e4543db   David S. Miller   ipv4: Make caller...
681
  	rt = ip_route_output_ports(dev_net(dev), &fl4, NULL,
78fbfd8a6   David S. Miller   ipv4: Create and ...
682
683
684
685
686
687
688
  				   dst, tiph->saddr,
  				   0, 0,
  				   IPPROTO_IPV6, RT_TOS(tos),
  				   tunnel->parms.link);
  	if (IS_ERR(rt)) {
  		dev->stats.tx_carrier_errors++;
  		goto tx_error_icmp;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
689
690
691
  	}
  	if (rt->rt_type != RTN_UNICAST) {
  		ip_rt_put(rt);
15fc1f705   Eric Dumazet   sit: percpu stats...
692
  		dev->stats.tx_carrier_errors++;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
693
694
  		goto tx_error_icmp;
  	}
d8d1f30b9   Changli Gao   net-next: remove ...
695
  	tdev = rt->dst.dev;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
696
697
698
  
  	if (tdev == dev) {
  		ip_rt_put(rt);
15fc1f705   Eric Dumazet   sit: percpu stats...
699
  		dev->stats.collisions++;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
700
701
  		goto tx_error;
  	}
292f4f3ce   Herbert Xu   sit: Clean up DF ...
702
  	if (df) {
d8d1f30b9   Changli Gao   net-next: remove ...
703
  		mtu = dst_mtu(&rt->dst) - sizeof(struct iphdr);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
704

292f4f3ce   Herbert Xu   sit: Clean up DF ...
705
  		if (mtu < 68) {
15fc1f705   Eric Dumazet   sit: percpu stats...
706
  			dev->stats.collisions++;
292f4f3ce   Herbert Xu   sit: Clean up DF ...
707
708
709
  			ip_rt_put(rt);
  			goto tx_error;
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
710

292f4f3ce   Herbert Xu   sit: Clean up DF ...
711
712
713
714
715
716
717
718
719
  		if (mtu < IPV6_MIN_MTU) {
  			mtu = IPV6_MIN_MTU;
  			df = 0;
  		}
  
  		if (tunnel->parms.iph.daddr && skb_dst(skb))
  			skb_dst(skb)->ops->update_pmtu(skb_dst(skb), mtu);
  
  		if (skb->len > mtu) {
3ffe533c8   Alexey Dobriyan   ipv6: drop unused...
720
  			icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu);
292f4f3ce   Herbert Xu   sit: Clean up DF ...
721
722
723
  			ip_rt_put(rt);
  			goto tx_error;
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
724
725
726
  	}
  
  	if (tunnel->err_count > 0) {
bb80087a9   Wei Yongjun   sit: used time_be...
727
728
  		if (time_before(jiffies,
  				tunnel->err_time + IPTUNNEL_ERR_TIMEO)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
729
730
731
732
733
734
735
736
737
738
  			tunnel->err_count--;
  			dst_link_failure(skb);
  		} else
  			tunnel->err_count = 0;
  	}
  
  	/*
  	 * Okay, now see if we can stuff it in the buffer as-is.
  	 */
  	max_headroom = LL_RESERVED_SPACE(tdev)+sizeof(struct iphdr);
cfbba49d8   Patrick McHardy   [NET]: Avoid copy...
739
740
  	if (skb_headroom(skb) < max_headroom || skb_shared(skb) ||
  	    (skb_cloned(skb) && !skb_clone_writable(skb, 0))) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
741
742
743
  		struct sk_buff *new_skb = skb_realloc_headroom(skb, max_headroom);
  		if (!new_skb) {
  			ip_rt_put(rt);
15fc1f705   Eric Dumazet   sit: percpu stats...
744
  			dev->stats.tx_dropped++;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
745
  			dev_kfree_skb(skb);
6ed106549   Patrick McHardy   net: use NETDEV_T...
746
  			return NETDEV_TX_OK;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
747
748
749
750
751
  		}
  		if (skb->sk)
  			skb_set_owner_w(new_skb, skb->sk);
  		dev_kfree_skb(skb);
  		skb = new_skb;
0660e03f6   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
752
  		iph6 = ipv6_hdr(skb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
753
  	}
b0e380b1d   Arnaldo Carvalho de Melo   [SK_BUFF]: unions...
754
  	skb->transport_header = skb->network_header;
e2d1bca7e   Arnaldo Carvalho de Melo   [SK_BUFF]: Use sk...
755
756
  	skb_push(skb, sizeof(struct iphdr));
  	skb_reset_network_header(skb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
757
  	memset(&(IPCB(skb)->opt), 0, sizeof(IPCB(skb)->opt));
8cdfab8a4   Patrick McHardy   [IPV4]: reset IPC...
758
  	IPCB(skb)->flags = 0;
adf30907d   Eric Dumazet   net: skb->dst acc...
759
  	skb_dst_drop(skb);
d8d1f30b9   Changli Gao   net-next: remove ...
760
  	skb_dst_set(skb, &rt->dst);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
761
762
763
764
  
  	/*
  	 *	Push down and install the IPIP header.
  	 */
eddc9ec53   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
765
  	iph 			=	ip_hdr(skb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
766
767
  	iph->version		=	4;
  	iph->ihl		=	sizeof(struct iphdr)>>2;
292f4f3ce   Herbert Xu   sit: Clean up DF ...
768
  	iph->frag_off		=	df;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
769
770
  	iph->protocol		=	IPPROTO_IPV6;
  	iph->tos		=	INET_ECN_encapsulate(tos, ipv6_get_dsfield(iph6));
301102cc8   David S. Miller   ipv6: Use flowi4-...
771
772
  	iph->daddr		=	fl4.daddr;
  	iph->saddr		=	fl4.saddr;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
773
774
775
776
777
  
  	if ((iph->ttl = tiph->ttl) == 0)
  		iph->ttl	=	iph6->hop_limit;
  
  	nf_reset(skb);
15fc1f705   Eric Dumazet   sit: percpu stats...
778
779
  	tstats = this_cpu_ptr(dev->tstats);
  	__IPTUNNEL_XMIT(tstats, &dev->stats);
6ed106549   Patrick McHardy   net: use NETDEV_T...
780
  	return NETDEV_TX_OK;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
781
782
783
784
  
  tx_error_icmp:
  	dst_link_failure(skb);
  tx_error:
15fc1f705   Eric Dumazet   sit: percpu stats...
785
  	dev->stats.tx_errors++;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
786
  	dev_kfree_skb(skb);
6ed106549   Patrick McHardy   net: use NETDEV_T...
787
  	return NETDEV_TX_OK;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
788
  }
8a4a50f98   Michal Schmidt   [IPV6] sit: Rebin...
789
790
791
792
  static void ipip6_tunnel_bind_dev(struct net_device *dev)
  {
  	struct net_device *tdev = NULL;
  	struct ip_tunnel *tunnel;
b71d1d426   Eric Dumazet   inet: constify ip...
793
  	const struct iphdr *iph;
31e4543db   David S. Miller   ipv4: Make caller...
794
  	struct flowi4 fl4;
8a4a50f98   Michal Schmidt   [IPV6] sit: Rebin...
795
796
797
798
799
  
  	tunnel = netdev_priv(dev);
  	iph = &tunnel->parms.iph;
  
  	if (iph->daddr) {
31e4543db   David S. Miller   ipv4: Make caller...
800
  		struct rtable *rt = ip_route_output_ports(dev_net(dev), &fl4, NULL,
78fbfd8a6   David S. Miller   ipv4: Create and ...
801
802
803
804
805
  							  iph->daddr, iph->saddr,
  							  0, 0,
  							  IPPROTO_IPV6,
  							  RT_TOS(iph->tos),
  							  tunnel->parms.link);
b23dd4fe4   David S. Miller   ipv4: Make output...
806
807
  
  		if (!IS_ERR(rt)) {
d8d1f30b9   Changli Gao   net-next: remove ...
808
  			tdev = rt->dst.dev;
8a4a50f98   Michal Schmidt   [IPV6] sit: Rebin...
809
810
811
812
813
814
  			ip_rt_put(rt);
  		}
  		dev->flags |= IFF_POINTOPOINT;
  	}
  
  	if (!tdev && tunnel->parms.link)
907a08c40   Pavel Emelyanov   [SIT]: Use proper...
815
  		tdev = __dev_get_by_index(dev_net(dev), tunnel->parms.link);
8a4a50f98   Michal Schmidt   [IPV6] sit: Rebin...
816
817
818
819
820
821
822
823
824
  
  	if (tdev) {
  		dev->hard_header_len = tdev->hard_header_len + sizeof(struct iphdr);
  		dev->mtu = tdev->mtu - sizeof(struct iphdr);
  		if (dev->mtu < IPV6_MIN_MTU)
  			dev->mtu = IPV6_MIN_MTU;
  	}
  	dev->iflink = tunnel->parms.link;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
825
826
827
828
829
  static int
  ipip6_tunnel_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd)
  {
  	int err = 0;
  	struct ip_tunnel_parm p;
fadf6bf06   Templin, Fred L   [IPV6] SIT: Add P...
830
  	struct ip_tunnel_prl prl;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
831
  	struct ip_tunnel *t;
ca8def148   Pavel Emelyanov   [SIT]: Add net/si...
832
833
  	struct net *net = dev_net(dev);
  	struct sit_net *sitn = net_generic(net, sit_net_id);
fa857afcf   YOSHIFUJI Hideaki / 吉藤英明   ipv6 sit: 6rd (IP...
834
835
836
  #ifdef CONFIG_IPV6_SIT_6RD
  	struct ip_tunnel_6rd ip6rd;
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
837
838
839
  
  	switch (cmd) {
  	case SIOCGETTUNNEL:
fa857afcf   YOSHIFUJI Hideaki / 吉藤英明   ipv6 sit: 6rd (IP...
840
841
842
  #ifdef CONFIG_IPV6_SIT_6RD
  	case SIOCGET6RD:
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
843
  		t = NULL;
cd3dbc194   Pavel Emelyanov   [SIT]: Make the f...
844
  		if (dev == sitn->fb_tunnel_dev) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
845
846
847
848
  			if (copy_from_user(&p, ifr->ifr_ifru.ifru_data, sizeof(p))) {
  				err = -EFAULT;
  				break;
  			}
ca8def148   Pavel Emelyanov   [SIT]: Add net/si...
849
  			t = ipip6_tunnel_locate(net, &p, 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
850
851
  		}
  		if (t == NULL)
2941a4863   Patrick McHardy   [NET]: Convert ne...
852
  			t = netdev_priv(dev);
fa857afcf   YOSHIFUJI Hideaki / 吉藤英明   ipv6 sit: 6rd (IP...
853
854
855
856
857
858
859
860
861
  
  		err = -EFAULT;
  		if (cmd == SIOCGETTUNNEL) {
  			memcpy(&p, &t->parms, sizeof(p));
  			if (copy_to_user(ifr->ifr_ifru.ifru_data, &p,
  					 sizeof(p)))
  				goto done;
  #ifdef CONFIG_IPV6_SIT_6RD
  		} else {
4e3fd7a06   Alexey Dobriyan   net: remove ipv6_...
862
  			ip6rd.prefix = t->ip6rd.prefix;
fa857afcf   YOSHIFUJI Hideaki / 吉藤英明   ipv6 sit: 6rd (IP...
863
864
865
866
867
868
869
870
871
  			ip6rd.relay_prefix = t->ip6rd.relay_prefix;
  			ip6rd.prefixlen = t->ip6rd.prefixlen;
  			ip6rd.relay_prefixlen = t->ip6rd.relay_prefixlen;
  			if (copy_to_user(ifr->ifr_ifru.ifru_data, &ip6rd,
  					 sizeof(ip6rd)))
  				goto done;
  #endif
  		}
  		err = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
  		break;
  
  	case SIOCADDTUNNEL:
  	case SIOCCHGTUNNEL:
  		err = -EPERM;
  		if (!capable(CAP_NET_ADMIN))
  			goto done;
  
  		err = -EFAULT;
  		if (copy_from_user(&p, ifr->ifr_ifru.ifru_data, sizeof(p)))
  			goto done;
  
  		err = -EINVAL;
  		if (p.iph.version != 4 || p.iph.protocol != IPPROTO_IPV6 ||
  		    p.iph.ihl != 5 || (p.iph.frag_off&htons(~IP_DF)))
  			goto done;
  		if (p.iph.ttl)
  			p.iph.frag_off |= htons(IP_DF);
ca8def148   Pavel Emelyanov   [SIT]: Add net/si...
890
  		t = ipip6_tunnel_locate(net, &p, cmd == SIOCADDTUNNEL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
891

cd3dbc194   Pavel Emelyanov   [SIT]: Make the f...
892
  		if (dev != sitn->fb_tunnel_dev && cmd == SIOCCHGTUNNEL) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
893
894
895
896
897
898
899
900
901
902
903
  			if (t != NULL) {
  				if (t->dev != dev) {
  					err = -EEXIST;
  					break;
  				}
  			} else {
  				if (((dev->flags&IFF_POINTOPOINT) && !p.iph.daddr) ||
  				    (!(dev->flags&IFF_POINTOPOINT) && p.iph.daddr)) {
  					err = -EINVAL;
  					break;
  				}
2941a4863   Patrick McHardy   [NET]: Convert ne...
904
  				t = netdev_priv(dev);
ca8def148   Pavel Emelyanov   [SIT]: Add net/si...
905
  				ipip6_tunnel_unlink(sitn, t);
74b0b85b8   Pavel Emelyanov   tunnels: Fix tunn...
906
  				synchronize_net();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
907
908
909
910
  				t->parms.iph.saddr = p.iph.saddr;
  				t->parms.iph.daddr = p.iph.daddr;
  				memcpy(dev->dev_addr, &p.iph.saddr, 4);
  				memcpy(dev->broadcast, &p.iph.daddr, 4);
ca8def148   Pavel Emelyanov   [SIT]: Add net/si...
911
  				ipip6_tunnel_link(sitn, t);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
912
913
914
915
916
917
918
919
920
  				netdev_state_change(dev);
  			}
  		}
  
  		if (t) {
  			err = 0;
  			if (cmd == SIOCCHGTUNNEL) {
  				t->parms.iph.ttl = p.iph.ttl;
  				t->parms.iph.tos = p.iph.tos;
8a4a50f98   Michal Schmidt   [IPV6] sit: Rebin...
921
922
923
924
925
  				if (t->parms.link != p.link) {
  					t->parms.link = p.link;
  					ipip6_tunnel_bind_dev(dev);
  					netdev_state_change(dev);
  				}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
926
927
928
929
930
931
932
933
934
935
936
  			}
  			if (copy_to_user(ifr->ifr_ifru.ifru_data, &t->parms, sizeof(p)))
  				err = -EFAULT;
  		} else
  			err = (cmd == SIOCADDTUNNEL ? -ENOBUFS : -ENOENT);
  		break;
  
  	case SIOCDELTUNNEL:
  		err = -EPERM;
  		if (!capable(CAP_NET_ADMIN))
  			goto done;
cd3dbc194   Pavel Emelyanov   [SIT]: Make the f...
937
  		if (dev == sitn->fb_tunnel_dev) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
938
939
940
941
  			err = -EFAULT;
  			if (copy_from_user(&p, ifr->ifr_ifru.ifru_data, sizeof(p)))
  				goto done;
  			err = -ENOENT;
ca8def148   Pavel Emelyanov   [SIT]: Add net/si...
942
  			if ((t = ipip6_tunnel_locate(net, &p, 0)) == NULL)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
943
944
  				goto done;
  			err = -EPERM;
cd3dbc194   Pavel Emelyanov   [SIT]: Make the f...
945
  			if (t == netdev_priv(sitn->fb_tunnel_dev))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
946
947
948
  				goto done;
  			dev = t->dev;
  		}
22f8cde5b   Stephen Hemminger   [NET]: unregister...
949
950
  		unregister_netdevice(dev);
  		err = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
951
  		break;
300aaeeaa   YOSHIFUJI Hideaki   [IPV6] SIT: Add S...
952
  	case SIOCGETPRL:
2b4743bd6   YOSHIFUJI Hideaki   ipv6 sit: Avoid e...
953
954
955
956
957
958
959
960
  		err = -EINVAL;
  		if (dev == sitn->fb_tunnel_dev)
  			goto done;
  		err = -ENOENT;
  		if (!(t = netdev_priv(dev)))
  			goto done;
  		err = ipip6_tunnel_get_prl(t, ifr->ifr_ifru.ifru_data);
  		break;
fadf6bf06   Templin, Fred L   [IPV6] SIT: Add P...
961
962
963
964
  	case SIOCADDPRL:
  	case SIOCDELPRL:
  	case SIOCCHGPRL:
  		err = -EPERM;
2b4743bd6   YOSHIFUJI Hideaki   ipv6 sit: Avoid e...
965
  		if (!capable(CAP_NET_ADMIN))
fadf6bf06   Templin, Fred L   [IPV6] SIT: Add P...
966
967
  			goto done;
  		err = -EINVAL;
cd3dbc194   Pavel Emelyanov   [SIT]: Make the f...
968
  		if (dev == sitn->fb_tunnel_dev)
fadf6bf06   Templin, Fred L   [IPV6] SIT: Add P...
969
970
971
972
973
974
975
  			goto done;
  		err = -EFAULT;
  		if (copy_from_user(&prl, ifr->ifr_ifru.ifru_data, sizeof(prl)))
  			goto done;
  		err = -ENOENT;
  		if (!(t = netdev_priv(dev)))
  			goto done;
300aaeeaa   YOSHIFUJI Hideaki   [IPV6] SIT: Add S...
976
  		switch (cmd) {
300aaeeaa   YOSHIFUJI Hideaki   [IPV6] SIT: Add S...
977
  		case SIOCDELPRL:
fadf6bf06   Templin, Fred L   [IPV6] SIT: Add P...
978
  			err = ipip6_tunnel_del_prl(t, &prl);
300aaeeaa   YOSHIFUJI Hideaki   [IPV6] SIT: Add S...
979
980
981
  			break;
  		case SIOCADDPRL:
  		case SIOCCHGPRL:
fadf6bf06   Templin, Fred L   [IPV6] SIT: Add P...
982
  			err = ipip6_tunnel_add_prl(t, &prl, cmd == SIOCCHGPRL);
300aaeeaa   YOSHIFUJI Hideaki   [IPV6] SIT: Add S...
983
984
  			break;
  		}
2b4743bd6   YOSHIFUJI Hideaki   ipv6 sit: Avoid e...
985
  		netdev_state_change(dev);
fadf6bf06   Templin, Fred L   [IPV6] SIT: Add P...
986
  		break;
fa857afcf   YOSHIFUJI Hideaki / 吉藤英明   ipv6 sit: 6rd (IP...
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
  #ifdef CONFIG_IPV6_SIT_6RD
  	case SIOCADD6RD:
  	case SIOCCHG6RD:
  	case SIOCDEL6RD:
  		err = -EPERM;
  		if (!capable(CAP_NET_ADMIN))
  			goto done;
  
  		err = -EFAULT;
  		if (copy_from_user(&ip6rd, ifr->ifr_ifru.ifru_data,
  				   sizeof(ip6rd)))
  			goto done;
  
  		t = netdev_priv(dev);
  
  		if (cmd != SIOCDEL6RD) {
  			struct in6_addr prefix;
  			__be32 relay_prefix;
  
  			err = -EINVAL;
  			if (ip6rd.relay_prefixlen > 32 ||
  			    ip6rd.prefixlen + (32 - ip6rd.relay_prefixlen) > 64)
  				goto done;
  
  			ipv6_addr_prefix(&prefix, &ip6rd.prefix,
  					 ip6rd.prefixlen);
  			if (!ipv6_addr_equal(&prefix, &ip6rd.prefix))
  				goto done;
91b2a3f9b   YOSHIFUJI Hideaki / 吉藤英明   ipv6 sit: Set rel...
1015
1016
1017
1018
1019
1020
  			if (ip6rd.relay_prefixlen)
  				relay_prefix = ip6rd.relay_prefix &
  					       htonl(0xffffffffUL <<
  						     (32 - ip6rd.relay_prefixlen));
  			else
  				relay_prefix = 0;
fa857afcf   YOSHIFUJI Hideaki / 吉藤英明   ipv6 sit: 6rd (IP...
1021
1022
  			if (relay_prefix != ip6rd.relay_prefix)
  				goto done;
4e3fd7a06   Alexey Dobriyan   net: remove ipv6_...
1023
  			t->ip6rd.prefix = prefix;
fa857afcf   YOSHIFUJI Hideaki / 吉藤英明   ipv6 sit: 6rd (IP...
1024
1025
1026
1027
  			t->ip6rd.relay_prefix = relay_prefix;
  			t->ip6rd.prefixlen = ip6rd.prefixlen;
  			t->ip6rd.relay_prefixlen = ip6rd.relay_prefixlen;
  		} else
e0c939481   YOSHIFUJI Hideaki / 吉藤英明   ipv6 sit: Ensure ...
1028
  			ipip6_tunnel_clone_6rd(dev, sitn);
fa857afcf   YOSHIFUJI Hideaki / 吉藤英明   ipv6 sit: 6rd (IP...
1029
1030
1031
1032
  
  		err = 0;
  		break;
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1033
1034
1035
1036
1037
1038
1039
  	default:
  		err = -EINVAL;
  	}
  
  done:
  	return err;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1040
1041
1042
1043
1044
1045
1046
  static int ipip6_tunnel_change_mtu(struct net_device *dev, int new_mtu)
  {
  	if (new_mtu < IPV6_MIN_MTU || new_mtu > 0xFFF8 - sizeof(struct iphdr))
  		return -EINVAL;
  	dev->mtu = new_mtu;
  	return 0;
  }
1326c3d5a   Stephen Hemminger   ipv6: convert tun...
1047
1048
1049
1050
1051
  static const struct net_device_ops ipip6_netdev_ops = {
  	.ndo_uninit	= ipip6_tunnel_uninit,
  	.ndo_start_xmit	= ipip6_tunnel_xmit,
  	.ndo_do_ioctl	= ipip6_tunnel_ioctl,
  	.ndo_change_mtu	= ipip6_tunnel_change_mtu,
15fc1f705   Eric Dumazet   sit: percpu stats...
1052
  	.ndo_get_stats	= ipip6_get_stats,
1326c3d5a   Stephen Hemminger   ipv6: convert tun...
1053
  };
15fc1f705   Eric Dumazet   sit: percpu stats...
1054
1055
1056
1057
1058
  static void ipip6_dev_free(struct net_device *dev)
  {
  	free_percpu(dev->tstats);
  	free_netdev(dev);
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1059
1060
  static void ipip6_tunnel_setup(struct net_device *dev)
  {
1326c3d5a   Stephen Hemminger   ipv6: convert tun...
1061
  	dev->netdev_ops		= &ipip6_netdev_ops;
15fc1f705   Eric Dumazet   sit: percpu stats...
1062
  	dev->destructor 	= ipip6_dev_free;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1063
1064
1065
  
  	dev->type		= ARPHRD_SIT;
  	dev->hard_header_len 	= LL_MAX_HEADER + sizeof(struct iphdr);
46f25dffb   Kris Katterjohn   [NET]: Change 150...
1066
  	dev->mtu		= ETH_DATA_LEN - sizeof(struct iphdr);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1067
  	dev->flags		= IFF_NOARP;
f2ba025b2   Sascha Hlusiak   sit: fix regressi...
1068
  	dev->priv_flags	       &= ~IFF_XMIT_DST_RELEASE;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1069
1070
  	dev->iflink		= 0;
  	dev->addr_len		= 4;
7a97146cc   Pavel Emelyanov   [SIT]: Allow to c...
1071
  	dev->features		|= NETIF_F_NETNS_LOCAL;
8df40d103   Eric Dumazet   sit: enable lockl...
1072
  	dev->features		|= NETIF_F_LLTX;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1073
  }
15fc1f705   Eric Dumazet   sit: percpu stats...
1074
  static int ipip6_tunnel_init(struct net_device *dev)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1075
  {
1326c3d5a   Stephen Hemminger   ipv6: convert tun...
1076
  	struct ip_tunnel *tunnel = netdev_priv(dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1077
1078
  
  	tunnel->dev = dev;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1079
1080
1081
  
  	memcpy(dev->dev_addr, &tunnel->parms.iph.saddr, 4);
  	memcpy(dev->broadcast, &tunnel->parms.iph.daddr, 4);
8a4a50f98   Michal Schmidt   [IPV6] sit: Rebin...
1082
  	ipip6_tunnel_bind_dev(dev);
15fc1f705   Eric Dumazet   sit: percpu stats...
1083
1084
1085
1086
1087
  	dev->tstats = alloc_percpu(struct pcpu_tstats);
  	if (!dev->tstats)
  		return -ENOMEM;
  
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1088
  }
dd4080ee5   Eric Dumazet   sit: fix percpu s...
1089
  static int __net_init ipip6_fb_tunnel_init(struct net_device *dev)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1090
  {
2941a4863   Patrick McHardy   [NET]: Convert ne...
1091
  	struct ip_tunnel *tunnel = netdev_priv(dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1092
  	struct iphdr *iph = &tunnel->parms.iph;
291821766   Pavel Emelyanov   [SIT]: Make tunne...
1093
1094
  	struct net *net = dev_net(dev);
  	struct sit_net *sitn = net_generic(net, sit_net_id);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1095
1096
1097
1098
1099
1100
1101
1102
  
  	tunnel->dev = dev;
  	strcpy(tunnel->parms.name, dev->name);
  
  	iph->version		= 4;
  	iph->protocol		= IPPROTO_IPV6;
  	iph->ihl		= 5;
  	iph->ttl		= 64;
dd4080ee5   Eric Dumazet   sit: fix percpu s...
1103
1104
1105
  	dev->tstats = alloc_percpu(struct pcpu_tstats);
  	if (!dev->tstats)
  		return -ENOMEM;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1106
  	dev_hold(dev);
cf778b00e   Eric Dumazet   net: reintroduce ...
1107
  	rcu_assign_pointer(sitn->tunnels_wc[0], tunnel);
dd4080ee5   Eric Dumazet   sit: fix percpu s...
1108
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1109
  }
6dcd814bd   Eric Dumazet   net: struct xfrm_...
1110
  static struct xfrm_tunnel sit_handler __read_mostly = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1111
1112
  	.handler	=	ipip6_rcv,
  	.err_handler	=	ipip6_err,
c73cb5a2d   Kazunori MIYAZAWA   [IPSEC]: make sit...
1113
  	.priority	=	1,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1114
  };
2c8c1e729   Alexey Dobriyan   net: spread __net...
1115
  static void __net_exit sit_destroy_tunnels(struct sit_net *sitn, struct list_head *head)
db44575f6   Alexey Kuznetsov   [NET]: fix oops a...
1116
1117
1118
1119
1120
1121
  {
  	int prio;
  
  	for (prio = 1; prio < 4; prio++) {
  		int h;
  		for (h = 0; h < HASH_SIZE; h++) {
753ea8e96   Eric Dumazet   net: ipv6: sit: f...
1122
  			struct ip_tunnel *t;
62808f912   Eric Dumazet   ipv6 sit: Optimiz...
1123

753ea8e96   Eric Dumazet   net: ipv6: sit: f...
1124
  			t = rtnl_dereference(sitn->tunnels[prio][h]);
62808f912   Eric Dumazet   ipv6 sit: Optimiz...
1125
1126
  			while (t != NULL) {
  				unregister_netdevice_queue(t->dev, head);
753ea8e96   Eric Dumazet   net: ipv6: sit: f...
1127
  				t = rtnl_dereference(t->next);
62808f912   Eric Dumazet   ipv6 sit: Optimiz...
1128
  			}
db44575f6   Alexey Kuznetsov   [NET]: fix oops a...
1129
1130
1131
  		}
  	}
  }
2c8c1e729   Alexey Dobriyan   net: spread __net...
1132
  static int __net_init sit_init_net(struct net *net)
8190d9009   Pavel Emelyanov   [SIT]: Introduce ...
1133
  {
671011720   Eric W. Biederman   net: Simplify ipi...
1134
  	struct sit_net *sitn = net_generic(net, sit_net_id);
72b36015b   Ted Feng   ipip, sit: copy p...
1135
  	struct ip_tunnel *t;
8190d9009   Pavel Emelyanov   [SIT]: Introduce ...
1136
  	int err;
8190d9009   Pavel Emelyanov   [SIT]: Introduce ...
1137

291821766   Pavel Emelyanov   [SIT]: Make tunne...
1138
1139
1140
1141
  	sitn->tunnels[0] = sitn->tunnels_wc;
  	sitn->tunnels[1] = sitn->tunnels_l;
  	sitn->tunnels[2] = sitn->tunnels_r;
  	sitn->tunnels[3] = sitn->tunnels_r_l;
cd3dbc194   Pavel Emelyanov   [SIT]: Make the f...
1142
1143
1144
1145
1146
1147
  	sitn->fb_tunnel_dev = alloc_netdev(sizeof(struct ip_tunnel), "sit0",
  					   ipip6_tunnel_setup);
  	if (!sitn->fb_tunnel_dev) {
  		err = -ENOMEM;
  		goto err_alloc_dev;
  	}
be77e5930   Alexey Dobriyan   net: fix tunnels ...
1148
  	dev_net_set(sitn->fb_tunnel_dev, net);
cd3dbc194   Pavel Emelyanov   [SIT]: Make the f...
1149

dd4080ee5   Eric Dumazet   sit: fix percpu s...
1150
1151
1152
  	err = ipip6_fb_tunnel_init(sitn->fb_tunnel_dev);
  	if (err)
  		goto err_dev_free;
e0c939481   YOSHIFUJI Hideaki / 吉藤英明   ipv6 sit: Ensure ...
1153
  	ipip6_tunnel_clone_6rd(sitn->fb_tunnel_dev, sitn);
cd3dbc194   Pavel Emelyanov   [SIT]: Make the f...
1154
1155
1156
  
  	if ((err = register_netdev(sitn->fb_tunnel_dev)))
  		goto err_reg_dev;
72b36015b   Ted Feng   ipip, sit: copy p...
1157
1158
1159
  	t = netdev_priv(sitn->fb_tunnel_dev);
  
  	strcpy(t->parms.name, sitn->fb_tunnel_dev->name);
8190d9009   Pavel Emelyanov   [SIT]: Introduce ...
1160
  	return 0;
cd3dbc194   Pavel Emelyanov   [SIT]: Make the f...
1161
  err_reg_dev:
1326c3d5a   Stephen Hemminger   ipv6: convert tun...
1162
  	dev_put(sitn->fb_tunnel_dev);
dd4080ee5   Eric Dumazet   sit: fix percpu s...
1163
1164
  err_dev_free:
  	ipip6_dev_free(sitn->fb_tunnel_dev);
cd3dbc194   Pavel Emelyanov   [SIT]: Make the f...
1165
  err_alloc_dev:
8190d9009   Pavel Emelyanov   [SIT]: Introduce ...
1166
1167
  	return err;
  }
2c8c1e729   Alexey Dobriyan   net: spread __net...
1168
  static void __net_exit sit_exit_net(struct net *net)
8190d9009   Pavel Emelyanov   [SIT]: Introduce ...
1169
  {
671011720   Eric W. Biederman   net: Simplify ipi...
1170
  	struct sit_net *sitn = net_generic(net, sit_net_id);
62808f912   Eric Dumazet   ipv6 sit: Optimiz...
1171
  	LIST_HEAD(list);
8190d9009   Pavel Emelyanov   [SIT]: Introduce ...
1172

cd3dbc194   Pavel Emelyanov   [SIT]: Make the f...
1173
  	rtnl_lock();
62808f912   Eric Dumazet   ipv6 sit: Optimiz...
1174
1175
1176
  	sit_destroy_tunnels(sitn, &list);
  	unregister_netdevice_queue(sitn->fb_tunnel_dev, &list);
  	unregister_netdevice_many(&list);
cd3dbc194   Pavel Emelyanov   [SIT]: Make the f...
1177
  	rtnl_unlock();
8190d9009   Pavel Emelyanov   [SIT]: Introduce ...
1178
1179
1180
1181
1182
  }
  
  static struct pernet_operations sit_net_ops = {
  	.init = sit_init_net,
  	.exit = sit_exit_net,
671011720   Eric W. Biederman   net: Simplify ipi...
1183
1184
  	.id   = &sit_net_id,
  	.size = sizeof(struct sit_net),
8190d9009   Pavel Emelyanov   [SIT]: Introduce ...
1185
  };
89c894581   Adrian Bunk   [IPV6] net/ipv6/s...
1186
  static void __exit sit_cleanup(void)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1187
  {
c73cb5a2d   Kazunori MIYAZAWA   [IPSEC]: make sit...
1188
  	xfrm4_tunnel_deregister(&sit_handler, AF_INET6);
db44575f6   Alexey Kuznetsov   [NET]: fix oops a...
1189

671011720   Eric W. Biederman   net: Simplify ipi...
1190
  	unregister_pernet_device(&sit_net_ops);
ef9a9d118   Eric Dumazet   ipv6 sit: RCU con...
1191
  	rcu_barrier(); /* Wait for completion of call_rcu()'s */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1192
  }
89c894581   Adrian Bunk   [IPV6] net/ipv6/s...
1193
  static int __init sit_init(void)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1194
1195
1196
1197
1198
  {
  	int err;
  
  	printk(KERN_INFO "IPv6 over IPv4 tunneling driver
  ");
671011720   Eric W. Biederman   net: Simplify ipi...
1199
  	err = register_pernet_device(&sit_net_ops);
8190d9009   Pavel Emelyanov   [SIT]: Introduce ...
1200
  	if (err < 0)
d5aa407f5   Alexey Dobriyan   tunnels: fix netn...
1201
1202
1203
1204
1205
1206
1207
  		return err;
  	err = xfrm4_tunnel_register(&sit_handler, AF_INET6);
  	if (err < 0) {
  		unregister_pernet_device(&sit_net_ops);
  		printk(KERN_INFO "sit init: Can't add protocol
  ");
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1208
  	return err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1209
  }
989e5b96e   Joerg Roedel   [IPV6]: Seperate ...
1210
1211
1212
  
  module_init(sit_init);
  module_exit(sit_cleanup);
39c850863   Jan Dittmer   [IPV6] sit: Add m...
1213
  MODULE_LICENSE("GPL");
8909c9ad8   Vasiliy Kulikov   net: don't allow ...
1214
  MODULE_ALIAS_NETDEV("sit0");