blob: 2f302d3ac9a3c27e4f29dd1f1c71811353db73d5 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09002 * Linux NET3: IP/IP protocol decoder.
Linus Torvalds1da177e2005-04-16 15:20:36 -07003 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07004 * Authors:
5 * Sam Lantinga (slouken@cs.ucdavis.edu) 02/01/95
6 *
7 * Fixes:
8 * Alan Cox : Merged and made usable non modular (its so tiny its silly as
9 * a module taking up 2 pages).
10 * Alan Cox : Fixed bug with 1.3.18 and IPIP not working (now needs to set skb->h.iph)
11 * to keep ip_forward happy.
12 * Alan Cox : More fixes for 1.3.21, and firewall fix. Maybe this will work soon 8).
13 * Kai Schulte : Fixed #defines for IP_FIREWALL->FIREWALL
14 * David Woodhouse : Perform some basic ICMP handling.
15 * IPIP Routing without decapsulation.
16 * Carlos Picoto : GRE over IP support
17 * Alexey Kuznetsov: Reworked. Really, now it is truncated version of ipv4/ip_gre.c.
18 * I do not want to merge them together.
19 *
20 * This program is free software; you can redistribute it and/or
21 * modify it under the terms of the GNU General Public License
22 * as published by the Free Software Foundation; either version
23 * 2 of the License, or (at your option) any later version.
24 *
25 */
26
27/* tunnel.c: an IP tunnel driver
28
29 The purpose of this driver is to provide an IP tunnel through
30 which you can tunnel network traffic transparently across subnets.
31
32 This was written by looking at Nick Holloway's dummy driver
33 Thanks for the great code!
34
35 -Sam Lantinga (slouken@cs.ucdavis.edu) 02/01/95
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +090036
Linus Torvalds1da177e2005-04-16 15:20:36 -070037 Minor tweaks:
38 Cleaned up the code a little and added some pre-1.3.0 tweaks.
39 dev->hard_header/hard_header_len changed to use no headers.
40 Comments/bracketing tweaked.
41 Made the tunnels use dev->name not tunnel: when error reporting.
42 Added tx_dropped stat
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +090043
Alan Cox113aa832008-10-13 19:01:08 -070044 -Alan Cox (alan@lxorguk.ukuu.org.uk) 21 March 95
Linus Torvalds1da177e2005-04-16 15:20:36 -070045
46 Reworked:
47 Changed to tunnel to destination gateway in addition to the
48 tunnel's pointopoint address
49 Almost completely rewritten
50 Note: There is currently no firewall or ICMP handling done.
51
52 -Sam Lantinga (slouken@cs.ucdavis.edu) 02/13/96
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +090053
Linus Torvalds1da177e2005-04-16 15:20:36 -070054*/
55
56/* Things I wish I had known when writing the tunnel driver:
57
58 When the tunnel_xmit() function is called, the skb contains the
59 packet to be sent (plus a great deal of extra info), and dev
60 contains the tunnel device that _we_ are.
61
62 When we are passed a packet, we are expected to fill in the
63 source address with our source IP address.
64
65 What is the proper way to allocate, copy and free a buffer?
66 After you allocate it, it is a "0 length" chunk of memory
67 starting at zero. If you want to add headers to the buffer
68 later, you'll have to call "skb_reserve(skb, amount)" with
69 the amount of memory you want reserved. Then, you call
70 "skb_put(skb, amount)" with the amount of space you want in
71 the buffer. skb_put() returns a pointer to the top (#0) of
72 that buffer. skb->len is set to the amount of space you have
73 "allocated" with skb_put(). You can then write up to skb->len
74 bytes to that buffer. If you need more, you can call skb_put()
75 again with the additional amount of space you need. You can
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +090076 find out how much more space you can allocate by calling
Linus Torvalds1da177e2005-04-16 15:20:36 -070077 "skb_tailroom(skb)".
78 Now, to add header space, call "skb_push(skb, header_len)".
79 This creates space at the beginning of the buffer and returns
80 a pointer to this new space. If later you need to strip a
81 header from a buffer, call "skb_pull(skb, header_len)".
82 skb_headroom() will return how much space is left at the top
83 of the buffer (before the main data). Remember, this headroom
84 space must be reserved before the skb_put() function is called.
85 */
86
87/*
88 This version of net/ipv4/ipip.c is cloned of net/ipv4/ip_gre.c
89
90 For comments look at net/ipv4/ip_gre.c --ANK
91 */
92
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +090093
Randy Dunlap4fc268d2006-01-11 12:17:47 -080094#include <linux/capability.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070095#include <linux/module.h>
96#include <linux/types.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070097#include <linux/kernel.h>
98#include <asm/uaccess.h>
99#include <linux/skbuff.h>
100#include <linux/netdevice.h>
101#include <linux/in.h>
102#include <linux/tcp.h>
103#include <linux/udp.h>
104#include <linux/if_arp.h>
105#include <linux/mroute.h>
106#include <linux/init.h>
107#include <linux/netfilter_ipv4.h>
Kris Katterjohn46f25df2006-01-05 16:35:42 -0800108#include <linux/if_ether.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -0700109
110#include <net/sock.h>
111#include <net/ip.h>
112#include <net/icmp.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -0700113#include <net/ipip.h>
114#include <net/inet_ecn.h>
115#include <net/xfrm.h>
Pavel Emelyanov10dc4c72008-04-16 01:03:13 -0700116#include <net/net_namespace.h>
117#include <net/netns/generic.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -0700118
119#define HASH_SIZE 16
Al Virod5a0a1e2006-11-08 00:23:14 -0800120#define HASH(addr) (((__force u32)addr^((__force u32)addr>>4))&0xF)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700121
Eric Dumazetf99189b2009-11-17 10:42:49 +0000122static int ipip_net_id __read_mostly;
Pavel Emelyanov10dc4c72008-04-16 01:03:13 -0700123struct ipip_net {
Pavel Emelyanov44d3c292008-04-16 01:05:32 -0700124 struct ip_tunnel *tunnels_r_l[HASH_SIZE];
125 struct ip_tunnel *tunnels_r[HASH_SIZE];
126 struct ip_tunnel *tunnels_l[HASH_SIZE];
127 struct ip_tunnel *tunnels_wc[1];
128 struct ip_tunnel **tunnels[4];
129
Pavel Emelyanovb9855c52008-04-16 01:04:13 -0700130 struct net_device *fb_tunnel_dev;
Pavel Emelyanov10dc4c72008-04-16 01:03:13 -0700131};
132
Stephen Hemminger23a12b12008-11-20 20:33:21 -0800133static void ipip_tunnel_init(struct net_device *dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700134static void ipip_tunnel_setup(struct net_device *dev);
135
Eric Dumazet8f95dd62009-10-23 05:42:02 +0000136/*
137 * Locking : hash tables are protected by RCU and a spinlock
138 */
139static DEFINE_SPINLOCK(ipip_lock);
140
141#define for_each_ip_tunnel_rcu(start) \
142 for (t = rcu_dereference(start); t; t = rcu_dereference(t->next))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700143
Pavel Emelyanovb9fae5c2008-04-16 01:04:35 -0700144static struct ip_tunnel * ipip_tunnel_lookup(struct net *net,
145 __be32 remote, __be32 local)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700146{
147 unsigned h0 = HASH(remote);
148 unsigned h1 = HASH(local);
149 struct ip_tunnel *t;
Pavel Emelyanov44d3c292008-04-16 01:05:32 -0700150 struct ipip_net *ipn = net_generic(net, ipip_net_id);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700151
Eric Dumazet8f95dd62009-10-23 05:42:02 +0000152 for_each_ip_tunnel_rcu(ipn->tunnels_r_l[h0 ^ h1])
Linus Torvalds1da177e2005-04-16 15:20:36 -0700153 if (local == t->parms.iph.saddr &&
154 remote == t->parms.iph.daddr && (t->dev->flags&IFF_UP))
155 return t;
Eric Dumazet8f95dd62009-10-23 05:42:02 +0000156
157 for_each_ip_tunnel_rcu(ipn->tunnels_r[h0])
Linus Torvalds1da177e2005-04-16 15:20:36 -0700158 if (remote == t->parms.iph.daddr && (t->dev->flags&IFF_UP))
159 return t;
Eric Dumazet8f95dd62009-10-23 05:42:02 +0000160
161 for_each_ip_tunnel_rcu(ipn->tunnels_l[h1])
Linus Torvalds1da177e2005-04-16 15:20:36 -0700162 if (local == t->parms.iph.saddr && (t->dev->flags&IFF_UP))
163 return t;
Eric Dumazet8f95dd62009-10-23 05:42:02 +0000164
165 t = rcu_dereference(ipn->tunnels_wc[0]);
166 if (t && (t->dev->flags&IFF_UP))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700167 return t;
168 return NULL;
169}
170
Pavel Emelyanovb9fae5c2008-04-16 01:04:35 -0700171static struct ip_tunnel **__ipip_bucket(struct ipip_net *ipn,
172 struct ip_tunnel_parm *parms)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700173{
YOSHIFUJI Hideaki87d1a162007-04-24 20:44:47 +0900174 __be32 remote = parms->iph.daddr;
175 __be32 local = parms->iph.saddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700176 unsigned h = 0;
177 int prio = 0;
178
179 if (remote) {
180 prio |= 2;
181 h ^= HASH(remote);
182 }
183 if (local) {
184 prio |= 1;
185 h ^= HASH(local);
186 }
Pavel Emelyanov44d3c292008-04-16 01:05:32 -0700187 return &ipn->tunnels[prio][h];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700188}
189
Pavel Emelyanovb9fae5c2008-04-16 01:04:35 -0700190static inline struct ip_tunnel **ipip_bucket(struct ipip_net *ipn,
191 struct ip_tunnel *t)
YOSHIFUJI Hideaki87d1a162007-04-24 20:44:47 +0900192{
Pavel Emelyanovb9fae5c2008-04-16 01:04:35 -0700193 return __ipip_bucket(ipn, &t->parms);
YOSHIFUJI Hideaki87d1a162007-04-24 20:44:47 +0900194}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700195
Pavel Emelyanovb9fae5c2008-04-16 01:04:35 -0700196static void ipip_tunnel_unlink(struct ipip_net *ipn, struct ip_tunnel *t)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700197{
198 struct ip_tunnel **tp;
199
Pavel Emelyanovb9fae5c2008-04-16 01:04:35 -0700200 for (tp = ipip_bucket(ipn, t); *tp; tp = &(*tp)->next) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700201 if (t == *tp) {
Eric Dumazet8f95dd62009-10-23 05:42:02 +0000202 spin_lock_bh(&ipip_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700203 *tp = t->next;
Eric Dumazet8f95dd62009-10-23 05:42:02 +0000204 spin_unlock_bh(&ipip_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700205 break;
206 }
207 }
208}
209
Pavel Emelyanovb9fae5c2008-04-16 01:04:35 -0700210static void ipip_tunnel_link(struct ipip_net *ipn, struct ip_tunnel *t)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700211{
Pavel Emelyanovb9fae5c2008-04-16 01:04:35 -0700212 struct ip_tunnel **tp = ipip_bucket(ipn, t);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700213
Eric Dumazet8f95dd62009-10-23 05:42:02 +0000214 spin_lock_bh(&ipip_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700215 t->next = *tp;
Eric Dumazet8f95dd62009-10-23 05:42:02 +0000216 rcu_assign_pointer(*tp, t);
217 spin_unlock_bh(&ipip_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700218}
219
Pavel Emelyanovb9fae5c2008-04-16 01:04:35 -0700220static struct ip_tunnel * ipip_tunnel_locate(struct net *net,
221 struct ip_tunnel_parm *parms, int create)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700222{
Al Virod5a0a1e2006-11-08 00:23:14 -0800223 __be32 remote = parms->iph.daddr;
224 __be32 local = parms->iph.saddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700225 struct ip_tunnel *t, **tp, *nt;
226 struct net_device *dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700227 char name[IFNAMSIZ];
Pavel Emelyanovb9fae5c2008-04-16 01:04:35 -0700228 struct ipip_net *ipn = net_generic(net, ipip_net_id);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700229
Pavel Emelyanovb9fae5c2008-04-16 01:04:35 -0700230 for (tp = __ipip_bucket(ipn, parms); (t = *tp) != NULL; tp = &t->next) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700231 if (local == t->parms.iph.saddr && remote == t->parms.iph.daddr)
232 return t;
233 }
234 if (!create)
235 return NULL;
236
237 if (parms->name[0])
238 strlcpy(name, parms->name, IFNAMSIZ);
Pavel Emelyanov34cc7ba2008-02-23 20:19:20 -0800239 else
240 sprintf(name, "tunl%%d");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700241
242 dev = alloc_netdev(sizeof(*t), name, ipip_tunnel_setup);
243 if (dev == NULL)
244 return NULL;
245
Pavel Emelyanov0a826402008-04-16 01:06:18 -0700246 dev_net_set(dev, net);
247
Pavel Emelyanovb37d4282008-02-26 23:51:04 -0800248 if (strchr(name, '%')) {
249 if (dev_alloc_name(dev, name) < 0)
250 goto failed_free;
251 }
252
Patrick McHardy2941a482006-01-08 22:05:26 -0800253 nt = netdev_priv(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700254 nt->parms = *parms;
255
Stephen Hemminger23a12b12008-11-20 20:33:21 -0800256 ipip_tunnel_init(dev);
257
Pavel Emelyanovb37d4282008-02-26 23:51:04 -0800258 if (register_netdevice(dev) < 0)
259 goto failed_free;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700260
261 dev_hold(dev);
Pavel Emelyanovb9fae5c2008-04-16 01:04:35 -0700262 ipip_tunnel_link(ipn, nt);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700263 return nt;
264
Pavel Emelyanovb37d4282008-02-26 23:51:04 -0800265failed_free:
266 free_netdev(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700267 return NULL;
268}
269
270static void ipip_tunnel_uninit(struct net_device *dev)
271{
Pavel Emelyanovb9855c52008-04-16 01:04:13 -0700272 struct net *net = dev_net(dev);
273 struct ipip_net *ipn = net_generic(net, ipip_net_id);
274
275 if (dev == ipn->fb_tunnel_dev) {
Eric Dumazet8f95dd62009-10-23 05:42:02 +0000276 spin_lock_bh(&ipip_lock);
Pavel Emelyanov44d3c292008-04-16 01:05:32 -0700277 ipn->tunnels_wc[0] = NULL;
Eric Dumazet8f95dd62009-10-23 05:42:02 +0000278 spin_unlock_bh(&ipip_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700279 } else
Pavel Emelyanovb9fae5c2008-04-16 01:04:35 -0700280 ipip_tunnel_unlink(ipn, netdev_priv(dev));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700281 dev_put(dev);
282}
283
Herbert Xud2acc342006-03-28 01:12:13 -0800284static int ipip_err(struct sk_buff *skb, u32 info)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700285{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700286
Rami Rosen071f92d2008-05-21 17:47:54 -0700287/* All the routers (except for Linux) return only
Linus Torvalds1da177e2005-04-16 15:20:36 -0700288 8 bytes of packet payload. It means, that precise relaying of
289 ICMP in the real Internet is absolutely infeasible.
290 */
Jianjun Kong5a5f3a82008-11-03 00:24:34 -0800291 struct iphdr *iph = (struct iphdr *)skb->data;
Arnaldo Carvalho de Melo88c76642007-03-13 14:43:18 -0300292 const int type = icmp_hdr(skb)->type;
293 const int code = icmp_hdr(skb)->code;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700294 struct ip_tunnel *t;
Herbert Xud2acc342006-03-28 01:12:13 -0800295 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700296
297 switch (type) {
298 default:
299 case ICMP_PARAMETERPROB:
Herbert Xud2acc342006-03-28 01:12:13 -0800300 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700301
302 case ICMP_DEST_UNREACH:
303 switch (code) {
304 case ICMP_SR_FAILED:
305 case ICMP_PORT_UNREACH:
306 /* Impossible event. */
Herbert Xud2acc342006-03-28 01:12:13 -0800307 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700308 case ICMP_FRAG_NEEDED:
309 /* Soft state for pmtu is maintained by IP core. */
Herbert Xud2acc342006-03-28 01:12:13 -0800310 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700311 default:
312 /* All others are translated to HOST_UNREACH.
313 rfc2003 contains "deep thoughts" about NET_UNREACH,
314 I believe they are just ether pollution. --ANK
315 */
316 break;
317 }
318 break;
319 case ICMP_TIME_EXCEEDED:
320 if (code != ICMP_EXC_TTL)
Herbert Xud2acc342006-03-28 01:12:13 -0800321 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700322 break;
323 }
324
Herbert Xud2acc342006-03-28 01:12:13 -0800325 err = -ENOENT;
326
Eric Dumazet8f95dd62009-10-23 05:42:02 +0000327 rcu_read_lock();
Pavel Emelyanovcec3ffa2008-04-16 01:05:03 -0700328 t = ipip_tunnel_lookup(dev_net(skb->dev), iph->daddr, iph->saddr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700329 if (t == NULL || t->parms.iph.daddr == 0)
330 goto out;
Herbert Xud2acc342006-03-28 01:12:13 -0800331
332 err = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700333 if (t->parms.iph.ttl == 0 && type == ICMP_TIME_EXCEEDED)
334 goto out;
335
Wei Yongjun26d94b42009-02-24 23:36:47 -0800336 if (time_before(jiffies, t->err_time + IPTUNNEL_ERR_TIMEO))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700337 t->err_count++;
338 else
339 t->err_count = 1;
340 t->err_time = jiffies;
341out:
Eric Dumazet8f95dd62009-10-23 05:42:02 +0000342 rcu_read_unlock();
Herbert Xud2acc342006-03-28 01:12:13 -0800343 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700344}
345
Arnaldo Carvalho de Meloeddc9ec2007-04-20 22:47:35 -0700346static inline void ipip_ecn_decapsulate(const struct iphdr *outer_iph,
347 struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700348{
Arnaldo Carvalho de Meloeddc9ec2007-04-20 22:47:35 -0700349 struct iphdr *inner_iph = ip_hdr(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700350
351 if (INET_ECN_is_ce(outer_iph->tos))
352 IP_ECN_set_ce(inner_iph);
353}
354
355static int ipip_rcv(struct sk_buff *skb)
356{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700357 struct ip_tunnel *tunnel;
Arnaldo Carvalho de Meloeddc9ec2007-04-20 22:47:35 -0700358 const struct iphdr *iph = ip_hdr(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700359
Eric Dumazet8f95dd62009-10-23 05:42:02 +0000360 rcu_read_lock();
Pavel Emelyanovcec3ffa2008-04-16 01:05:03 -0700361 if ((tunnel = ipip_tunnel_lookup(dev_net(skb->dev),
Pavel Emelyanovb9fae5c2008-04-16 01:04:35 -0700362 iph->saddr, iph->daddr)) != NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700363 if (!xfrm4_policy_check(NULL, XFRM_POLICY_IN, skb)) {
Eric Dumazet8f95dd62009-10-23 05:42:02 +0000364 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700365 kfree_skb(skb);
366 return 0;
367 }
368
369 secpath_reset(skb);
370
Arnaldo Carvalho de Melob0e380b2007-04-10 21:21:55 -0700371 skb->mac_header = skb->network_header;
Arnaldo Carvalho de Meloc1d2bbe2007-04-10 20:45:18 -0700372 skb_reset_network_header(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700373 skb->protocol = htons(ETH_P_IP);
374 skb->pkt_type = PACKET_HOST;
375
Pavel Emelyanov50f59ce2008-05-21 14:15:16 -0700376 tunnel->dev->stats.rx_packets++;
377 tunnel->dev->stats.rx_bytes += skb->len;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700378 skb->dev = tunnel->dev;
Eric Dumazetadf30902009-06-02 05:19:30 +0000379 skb_dst_drop(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700380 nf_reset(skb);
381 ipip_ecn_decapsulate(iph, skb);
382 netif_rx(skb);
Eric Dumazet8f95dd62009-10-23 05:42:02 +0000383 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700384 return 0;
385 }
Eric Dumazet8f95dd62009-10-23 05:42:02 +0000386 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700387
Linus Torvalds1da177e2005-04-16 15:20:36 -0700388 return -1;
389}
390
391/*
392 * This function assumes it is being called from dev_queue_xmit()
393 * and that skb is filled properly by that function.
394 */
395
Stephen Hemminger6fef4c02009-08-31 19:50:41 +0000396static netdev_tx_t ipip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700397{
Patrick McHardy2941a482006-01-08 22:05:26 -0800398 struct ip_tunnel *tunnel = netdev_priv(dev);
Eric Dumazet0bfbedb2009-10-05 00:11:22 -0700399 struct net_device_stats *stats = &dev->stats;
400 struct netdev_queue *txq = netdev_get_tx_queue(dev, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700401 struct iphdr *tiph = &tunnel->parms.iph;
402 u8 tos = tunnel->parms.iph.tos;
Al Virod5a0a1e2006-11-08 00:23:14 -0800403 __be16 df = tiph->frag_off;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700404 struct rtable *rt; /* Route to the other host */
405 struct net_device *tdev; /* Device to other host */
Arnaldo Carvalho de Meloeddc9ec2007-04-20 22:47:35 -0700406 struct iphdr *old_iph = ip_hdr(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700407 struct iphdr *iph; /* Our new IP header */
Chuck Leverc2636b42007-10-23 21:07:32 -0700408 unsigned int max_headroom; /* The extra header space needed */
Al Virod5a0a1e2006-11-08 00:23:14 -0800409 __be32 dst = tiph->daddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700410 int mtu;
411
Linus Torvalds1da177e2005-04-16 15:20:36 -0700412 if (skb->protocol != htons(ETH_P_IP))
413 goto tx_error;
414
415 if (tos&1)
416 tos = old_iph->tos;
417
418 if (!dst) {
419 /* NBMA tunnel */
Eric Dumazet511c3f92009-06-02 05:14:27 +0000420 if ((rt = skb_rtable(skb)) == NULL) {
Pavel Emelyanov50f59ce2008-05-21 14:15:16 -0700421 stats->tx_fifo_errors++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700422 goto tx_error;
423 }
424 if ((dst = rt->rt_gateway) == 0)
425 goto tx_error_icmp;
426 }
427
428 {
429 struct flowi fl = { .oif = tunnel->parms.link,
430 .nl_u = { .ip4_u =
431 { .daddr = dst,
432 .saddr = tiph->saddr,
433 .tos = RT_TOS(tos) } },
434 .proto = IPPROTO_IPIP };
Pavel Emelyanovb99f0152008-04-16 01:05:57 -0700435 if (ip_route_output_key(dev_net(dev), &rt, &fl)) {
Pavel Emelyanov50f59ce2008-05-21 14:15:16 -0700436 stats->tx_carrier_errors++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700437 goto tx_error_icmp;
438 }
439 }
440 tdev = rt->u.dst.dev;
441
442 if (tdev == dev) {
443 ip_rt_put(rt);
Pavel Emelyanov50f59ce2008-05-21 14:15:16 -0700444 stats->collisions++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700445 goto tx_error;
446 }
447
Herbert Xu23ca0c92009-11-06 10:37:41 +0000448 df |= old_iph->frag_off & htons(IP_DF);
449
450 if (df) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700451 mtu = dst_mtu(&rt->u.dst) - sizeof(struct iphdr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700452
Herbert Xu23ca0c92009-11-06 10:37:41 +0000453 if (mtu < 68) {
454 stats->collisions++;
455 ip_rt_put(rt);
456 goto tx_error;
457 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700458
Herbert Xu23ca0c92009-11-06 10:37:41 +0000459 if (skb_dst(skb))
460 skb_dst(skb)->ops->update_pmtu(skb_dst(skb), mtu);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700461
Herbert Xu23ca0c92009-11-06 10:37:41 +0000462 if ((old_iph->frag_off & htons(IP_DF)) &&
463 mtu < ntohs(old_iph->tot_len)) {
464 icmp_send(skb, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED,
465 htonl(mtu));
466 ip_rt_put(rt);
467 goto tx_error;
468 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700469 }
470
471 if (tunnel->err_count > 0) {
Wei Yongjun26d94b42009-02-24 23:36:47 -0800472 if (time_before(jiffies,
473 tunnel->err_time + IPTUNNEL_ERR_TIMEO)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700474 tunnel->err_count--;
475 dst_link_failure(skb);
476 } else
477 tunnel->err_count = 0;
478 }
479
480 /*
481 * Okay, now see if we can stuff it in the buffer as-is.
482 */
483 max_headroom = (LL_RESERVED_SPACE(tdev)+sizeof(struct iphdr));
484
Patrick McHardycfbba492007-07-09 15:33:40 -0700485 if (skb_headroom(skb) < max_headroom || skb_shared(skb) ||
486 (skb_cloned(skb) && !skb_clone_writable(skb, 0))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700487 struct sk_buff *new_skb = skb_realloc_headroom(skb, max_headroom);
488 if (!new_skb) {
489 ip_rt_put(rt);
Eric Dumazet0bfbedb2009-10-05 00:11:22 -0700490 txq->tx_dropped++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700491 dev_kfree_skb(skb);
Patrick McHardy6ed10652009-06-23 06:03:08 +0000492 return NETDEV_TX_OK;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700493 }
494 if (skb->sk)
495 skb_set_owner_w(new_skb, skb->sk);
496 dev_kfree_skb(skb);
497 skb = new_skb;
Arnaldo Carvalho de Meloeddc9ec2007-04-20 22:47:35 -0700498 old_iph = ip_hdr(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700499 }
500
Arnaldo Carvalho de Melob0e380b2007-04-10 21:21:55 -0700501 skb->transport_header = skb->network_header;
Arnaldo Carvalho de Meloe2d1bca2007-04-10 20:46:21 -0700502 skb_push(skb, sizeof(struct iphdr));
503 skb_reset_network_header(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700504 memset(&(IPCB(skb)->opt), 0, sizeof(IPCB(skb)->opt));
Patrick McHardy48d5cad2006-02-15 15:10:22 -0800505 IPCB(skb)->flags &= ~(IPSKB_XFRM_TUNNEL_SIZE | IPSKB_XFRM_TRANSFORMED |
506 IPSKB_REROUTED);
Eric Dumazetadf30902009-06-02 05:19:30 +0000507 skb_dst_drop(skb);
508 skb_dst_set(skb, &rt->u.dst);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700509
510 /*
511 * Push down and install the IPIP header.
512 */
513
Arnaldo Carvalho de Meloeddc9ec2007-04-20 22:47:35 -0700514 iph = ip_hdr(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700515 iph->version = 4;
516 iph->ihl = sizeof(struct iphdr)>>2;
517 iph->frag_off = df;
518 iph->protocol = IPPROTO_IPIP;
519 iph->tos = INET_ECN_encapsulate(tos, old_iph->tos);
520 iph->daddr = rt->rt_dst;
521 iph->saddr = rt->rt_src;
522
523 if ((iph->ttl = tiph->ttl) == 0)
524 iph->ttl = old_iph->ttl;
525
526 nf_reset(skb);
527
528 IPTUNNEL_XMIT();
Patrick McHardy6ed10652009-06-23 06:03:08 +0000529 return NETDEV_TX_OK;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700530
531tx_error_icmp:
532 dst_link_failure(skb);
533tx_error:
534 stats->tx_errors++;
535 dev_kfree_skb(skb);
Patrick McHardy6ed10652009-06-23 06:03:08 +0000536 return NETDEV_TX_OK;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700537}
538
Michal Schmidt55339952007-12-12 11:01:43 -0800539static void ipip_tunnel_bind_dev(struct net_device *dev)
540{
541 struct net_device *tdev = NULL;
542 struct ip_tunnel *tunnel;
543 struct iphdr *iph;
544
545 tunnel = netdev_priv(dev);
546 iph = &tunnel->parms.iph;
547
548 if (iph->daddr) {
549 struct flowi fl = { .oif = tunnel->parms.link,
550 .nl_u = { .ip4_u =
551 { .daddr = iph->daddr,
552 .saddr = iph->saddr,
553 .tos = RT_TOS(iph->tos) } },
554 .proto = IPPROTO_IPIP };
555 struct rtable *rt;
Pavel Emelyanovb99f0152008-04-16 01:05:57 -0700556 if (!ip_route_output_key(dev_net(dev), &rt, &fl)) {
Michal Schmidt55339952007-12-12 11:01:43 -0800557 tdev = rt->u.dst.dev;
558 ip_rt_put(rt);
559 }
560 dev->flags |= IFF_POINTOPOINT;
561 }
562
563 if (!tdev && tunnel->parms.link)
Pavel Emelyanovb99f0152008-04-16 01:05:57 -0700564 tdev = __dev_get_by_index(dev_net(dev), tunnel->parms.link);
Michal Schmidt55339952007-12-12 11:01:43 -0800565
566 if (tdev) {
567 dev->hard_header_len = tdev->hard_header_len + sizeof(struct iphdr);
568 dev->mtu = tdev->mtu - sizeof(struct iphdr);
569 }
570 dev->iflink = tunnel->parms.link;
571}
572
Linus Torvalds1da177e2005-04-16 15:20:36 -0700573static int
574ipip_tunnel_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd)
575{
576 int err = 0;
577 struct ip_tunnel_parm p;
578 struct ip_tunnel *t;
Pavel Emelyanovb9855c52008-04-16 01:04:13 -0700579 struct net *net = dev_net(dev);
580 struct ipip_net *ipn = net_generic(net, ipip_net_id);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700581
582 switch (cmd) {
583 case SIOCGETTUNNEL:
584 t = NULL;
Pavel Emelyanovb9855c52008-04-16 01:04:13 -0700585 if (dev == ipn->fb_tunnel_dev) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700586 if (copy_from_user(&p, ifr->ifr_ifru.ifru_data, sizeof(p))) {
587 err = -EFAULT;
588 break;
589 }
Pavel Emelyanovb9fae5c2008-04-16 01:04:35 -0700590 t = ipip_tunnel_locate(net, &p, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700591 }
592 if (t == NULL)
Patrick McHardy2941a482006-01-08 22:05:26 -0800593 t = netdev_priv(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700594 memcpy(&p, &t->parms, sizeof(p));
595 if (copy_to_user(ifr->ifr_ifru.ifru_data, &p, sizeof(p)))
596 err = -EFAULT;
597 break;
598
599 case SIOCADDTUNNEL:
600 case SIOCCHGTUNNEL:
601 err = -EPERM;
602 if (!capable(CAP_NET_ADMIN))
603 goto done;
604
605 err = -EFAULT;
606 if (copy_from_user(&p, ifr->ifr_ifru.ifru_data, sizeof(p)))
607 goto done;
608
609 err = -EINVAL;
610 if (p.iph.version != 4 || p.iph.protocol != IPPROTO_IPIP ||
611 p.iph.ihl != 5 || (p.iph.frag_off&htons(~IP_DF)))
612 goto done;
613 if (p.iph.ttl)
614 p.iph.frag_off |= htons(IP_DF);
615
Pavel Emelyanovb9fae5c2008-04-16 01:04:35 -0700616 t = ipip_tunnel_locate(net, &p, cmd == SIOCADDTUNNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700617
Pavel Emelyanovb9855c52008-04-16 01:04:13 -0700618 if (dev != ipn->fb_tunnel_dev && cmd == SIOCCHGTUNNEL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700619 if (t != NULL) {
620 if (t->dev != dev) {
621 err = -EEXIST;
622 break;
623 }
624 } else {
625 if (((dev->flags&IFF_POINTOPOINT) && !p.iph.daddr) ||
626 (!(dev->flags&IFF_POINTOPOINT) && p.iph.daddr)) {
627 err = -EINVAL;
628 break;
629 }
Patrick McHardy2941a482006-01-08 22:05:26 -0800630 t = netdev_priv(dev);
Pavel Emelyanovb9fae5c2008-04-16 01:04:35 -0700631 ipip_tunnel_unlink(ipn, t);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700632 t->parms.iph.saddr = p.iph.saddr;
633 t->parms.iph.daddr = p.iph.daddr;
634 memcpy(dev->dev_addr, &p.iph.saddr, 4);
635 memcpy(dev->broadcast, &p.iph.daddr, 4);
Pavel Emelyanovb9fae5c2008-04-16 01:04:35 -0700636 ipip_tunnel_link(ipn, t);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700637 netdev_state_change(dev);
638 }
639 }
640
641 if (t) {
642 err = 0;
643 if (cmd == SIOCCHGTUNNEL) {
644 t->parms.iph.ttl = p.iph.ttl;
645 t->parms.iph.tos = p.iph.tos;
646 t->parms.iph.frag_off = p.iph.frag_off;
Michal Schmidt55339952007-12-12 11:01:43 -0800647 if (t->parms.link != p.link) {
648 t->parms.link = p.link;
649 ipip_tunnel_bind_dev(dev);
650 netdev_state_change(dev);
651 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700652 }
653 if (copy_to_user(ifr->ifr_ifru.ifru_data, &t->parms, sizeof(p)))
654 err = -EFAULT;
655 } else
656 err = (cmd == SIOCADDTUNNEL ? -ENOBUFS : -ENOENT);
657 break;
658
659 case SIOCDELTUNNEL:
660 err = -EPERM;
661 if (!capable(CAP_NET_ADMIN))
662 goto done;
663
Pavel Emelyanovb9855c52008-04-16 01:04:13 -0700664 if (dev == ipn->fb_tunnel_dev) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700665 err = -EFAULT;
666 if (copy_from_user(&p, ifr->ifr_ifru.ifru_data, sizeof(p)))
667 goto done;
668 err = -ENOENT;
Pavel Emelyanovb9fae5c2008-04-16 01:04:35 -0700669 if ((t = ipip_tunnel_locate(net, &p, 0)) == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700670 goto done;
671 err = -EPERM;
Pavel Emelyanovb9855c52008-04-16 01:04:13 -0700672 if (t->dev == ipn->fb_tunnel_dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700673 goto done;
674 dev = t->dev;
675 }
Stephen Hemminger22f8cde2007-02-07 00:09:58 -0800676 unregister_netdevice(dev);
677 err = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700678 break;
679
680 default:
681 err = -EINVAL;
682 }
683
684done:
685 return err;
686}
687
Linus Torvalds1da177e2005-04-16 15:20:36 -0700688static int ipip_tunnel_change_mtu(struct net_device *dev, int new_mtu)
689{
690 if (new_mtu < 68 || new_mtu > 0xFFF8 - sizeof(struct iphdr))
691 return -EINVAL;
692 dev->mtu = new_mtu;
693 return 0;
694}
695
Stephen Hemminger23a12b12008-11-20 20:33:21 -0800696static const struct net_device_ops ipip_netdev_ops = {
697 .ndo_uninit = ipip_tunnel_uninit,
698 .ndo_start_xmit = ipip_tunnel_xmit,
699 .ndo_do_ioctl = ipip_tunnel_ioctl,
700 .ndo_change_mtu = ipip_tunnel_change_mtu,
701
702};
703
Linus Torvalds1da177e2005-04-16 15:20:36 -0700704static void ipip_tunnel_setup(struct net_device *dev)
705{
Stephen Hemminger23a12b12008-11-20 20:33:21 -0800706 dev->netdev_ops = &ipip_netdev_ops;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700707 dev->destructor = free_netdev;
708
709 dev->type = ARPHRD_TUNNEL;
710 dev->hard_header_len = LL_MAX_HEADER + sizeof(struct iphdr);
Kris Katterjohn46f25df2006-01-05 16:35:42 -0800711 dev->mtu = ETH_DATA_LEN - sizeof(struct iphdr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700712 dev->flags = IFF_NOARP;
713 dev->iflink = 0;
714 dev->addr_len = 4;
Pavel Emelyanov0a826402008-04-16 01:06:18 -0700715 dev->features |= NETIF_F_NETNS_LOCAL;
Eric Dumazet28e72212009-05-28 10:44:30 +0000716 dev->priv_flags &= ~IFF_XMIT_DST_RELEASE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700717}
718
Stephen Hemminger23a12b12008-11-20 20:33:21 -0800719static void ipip_tunnel_init(struct net_device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700720{
Stephen Hemminger23a12b12008-11-20 20:33:21 -0800721 struct ip_tunnel *tunnel = netdev_priv(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700722
723 tunnel->dev = dev;
724 strcpy(tunnel->parms.name, dev->name);
725
726 memcpy(dev->dev_addr, &tunnel->parms.iph.saddr, 4);
727 memcpy(dev->broadcast, &tunnel->parms.iph.daddr, 4);
728
Michal Schmidt55339952007-12-12 11:01:43 -0800729 ipip_tunnel_bind_dev(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700730}
731
Alexey Dobriyan2c8c1e72010-01-17 03:35:32 +0000732static void __net_init ipip_fb_tunnel_init(struct net_device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700733{
Patrick McHardy2941a482006-01-08 22:05:26 -0800734 struct ip_tunnel *tunnel = netdev_priv(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700735 struct iphdr *iph = &tunnel->parms.iph;
Pavel Emelyanov44d3c292008-04-16 01:05:32 -0700736 struct ipip_net *ipn = net_generic(dev_net(dev), ipip_net_id);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700737
738 tunnel->dev = dev;
739 strcpy(tunnel->parms.name, dev->name);
740
741 iph->version = 4;
742 iph->protocol = IPPROTO_IPIP;
743 iph->ihl = 5;
744
745 dev_hold(dev);
Pavel Emelyanov44d3c292008-04-16 01:05:32 -0700746 ipn->tunnels_wc[0] = tunnel;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700747}
748
749static struct xfrm_tunnel ipip_handler = {
750 .handler = ipip_rcv,
751 .err_handler = ipip_err,
Herbert Xud2acc342006-03-28 01:12:13 -0800752 .priority = 1,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700753};
754
Stephen Hemminger5747a1a2009-02-22 00:02:08 -0800755static const char banner[] __initconst =
Linus Torvalds1da177e2005-04-16 15:20:36 -0700756 KERN_INFO "IPv4 over IPv4 tunneling driver\n";
757
Eric Dumazet0694c4c2009-10-27 07:06:59 +0000758static void ipip_destroy_tunnels(struct ipip_net *ipn, struct list_head *head)
Pavel Emelyanov44d3c292008-04-16 01:05:32 -0700759{
760 int prio;
761
762 for (prio = 1; prio < 4; prio++) {
763 int h;
764 for (h = 0; h < HASH_SIZE; h++) {
Eric Dumazet0694c4c2009-10-27 07:06:59 +0000765 struct ip_tunnel *t = ipn->tunnels[prio][h];
766
767 while (t != NULL) {
768 unregister_netdevice_queue(t->dev, head);
769 t = t->next;
770 }
Pavel Emelyanov44d3c292008-04-16 01:05:32 -0700771 }
772 }
773}
774
Alexey Dobriyan2c8c1e72010-01-17 03:35:32 +0000775static int __net_init ipip_init_net(struct net *net)
Pavel Emelyanov10dc4c72008-04-16 01:03:13 -0700776{
Eric W. Biederman86de8a62009-11-29 15:46:14 +0000777 struct ipip_net *ipn = net_generic(net, ipip_net_id);
Pavel Emelyanov10dc4c72008-04-16 01:03:13 -0700778 int err;
Pavel Emelyanov10dc4c72008-04-16 01:03:13 -0700779
Pavel Emelyanov44d3c292008-04-16 01:05:32 -0700780 ipn->tunnels[0] = ipn->tunnels_wc;
781 ipn->tunnels[1] = ipn->tunnels_l;
782 ipn->tunnels[2] = ipn->tunnels_r;
783 ipn->tunnels[3] = ipn->tunnels_r_l;
784
Pavel Emelyanovb9855c52008-04-16 01:04:13 -0700785 ipn->fb_tunnel_dev = alloc_netdev(sizeof(struct ip_tunnel),
786 "tunl0",
787 ipip_tunnel_setup);
788 if (!ipn->fb_tunnel_dev) {
789 err = -ENOMEM;
790 goto err_alloc_dev;
791 }
Alexey Dobriyanbe77e592008-11-23 17:26:26 -0800792 dev_net_set(ipn->fb_tunnel_dev, net);
Pavel Emelyanovb9855c52008-04-16 01:04:13 -0700793
Stephen Hemminger23a12b12008-11-20 20:33:21 -0800794 ipip_fb_tunnel_init(ipn->fb_tunnel_dev);
Pavel Emelyanovb9855c52008-04-16 01:04:13 -0700795
796 if ((err = register_netdev(ipn->fb_tunnel_dev)))
797 goto err_reg_dev;
798
Pavel Emelyanov10dc4c72008-04-16 01:03:13 -0700799 return 0;
800
Pavel Emelyanovb9855c52008-04-16 01:04:13 -0700801err_reg_dev:
802 free_netdev(ipn->fb_tunnel_dev);
803err_alloc_dev:
804 /* nothing */
Pavel Emelyanov10dc4c72008-04-16 01:03:13 -0700805 return err;
806}
807
Alexey Dobriyan2c8c1e72010-01-17 03:35:32 +0000808static void __net_exit ipip_exit_net(struct net *net)
Pavel Emelyanov10dc4c72008-04-16 01:03:13 -0700809{
Eric W. Biederman86de8a62009-11-29 15:46:14 +0000810 struct ipip_net *ipn = net_generic(net, ipip_net_id);
Eric Dumazet0694c4c2009-10-27 07:06:59 +0000811 LIST_HEAD(list);
Pavel Emelyanov10dc4c72008-04-16 01:03:13 -0700812
Pavel Emelyanovb9855c52008-04-16 01:04:13 -0700813 rtnl_lock();
Eric Dumazet0694c4c2009-10-27 07:06:59 +0000814 ipip_destroy_tunnels(ipn, &list);
815 unregister_netdevice_queue(ipn->fb_tunnel_dev, &list);
816 unregister_netdevice_many(&list);
Pavel Emelyanovb9855c52008-04-16 01:04:13 -0700817 rtnl_unlock();
Pavel Emelyanov10dc4c72008-04-16 01:03:13 -0700818}
819
820static struct pernet_operations ipip_net_ops = {
821 .init = ipip_init_net,
822 .exit = ipip_exit_net,
Eric W. Biederman86de8a62009-11-29 15:46:14 +0000823 .id = &ipip_net_id,
824 .size = sizeof(struct ipip_net),
Pavel Emelyanov10dc4c72008-04-16 01:03:13 -0700825};
826
Linus Torvalds1da177e2005-04-16 15:20:36 -0700827static int __init ipip_init(void)
828{
829 int err;
830
831 printk(banner);
832
Eric W. Biederman86de8a62009-11-29 15:46:14 +0000833 err = register_pernet_device(&ipip_net_ops);
Alexey Dobriyand5aa4072010-02-16 09:05:04 +0000834 if (err < 0)
835 return err;
836 err = xfrm4_tunnel_register(&ipip_handler, AF_INET);
837 if (err < 0) {
838 unregister_pernet_device(&ipip_net_ops);
839 printk(KERN_INFO "ipip init: can't register tunnel\n");
840 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700841 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700842}
843
844static void __exit ipip_fini(void)
845{
Kazunori MIYAZAWAc0d56402007-02-13 12:54:47 -0800846 if (xfrm4_tunnel_deregister(&ipip_handler, AF_INET))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700847 printk(KERN_INFO "ipip close: can't deregister tunnel\n");
848
Eric W. Biederman86de8a62009-11-29 15:46:14 +0000849 unregister_pernet_device(&ipip_net_ops);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700850}
851
852module_init(ipip_init);
853module_exit(ipip_fini);
854MODULE_LICENSE("GPL");