Blame view

net/ipv4/ipip.c 17.9 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
  /*
e905a9eda   YOSHIFUJI Hideaki   [NET] IPV4: Fix w...
2
   *	Linux NET3:	IP/IP protocol decoder.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3
   *
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
   *	Authors:
   *		Sam Lantinga (slouken@cs.ucdavis.edu)  02/01/95
   *
   *	Fixes:
   *		Alan Cox	:	Merged and made usable non modular (its so tiny its silly as
   *					a module taking up 2 pages).
   *		Alan Cox	: 	Fixed bug with 1.3.18 and IPIP not working (now needs to set skb->h.iph)
   *					to keep ip_forward happy.
   *		Alan Cox	:	More fixes for 1.3.21, and firewall fix. Maybe this will work soon 8).
   *		Kai Schulte	:	Fixed #defines for IP_FIREWALL->FIREWALL
   *              David Woodhouse :       Perform some basic ICMP handling.
   *                                      IPIP Routing without decapsulation.
   *              Carlos Picoto   :       GRE over IP support
   *		Alexey Kuznetsov:	Reworked. Really, now it is truncated version of ipv4/ip_gre.c.
   *					I do not want to merge them together.
   *
   *	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.
   *
   */
  
  /* tunnel.c: an IP tunnel driver
  
  	The purpose of this driver is to provide an IP tunnel through
  	which you can tunnel network traffic transparently across subnets.
  
  	This was written by looking at Nick Holloway's dummy driver
  	Thanks for the great code!
  
  		-Sam Lantinga	(slouken@cs.ucdavis.edu)  02/01/95
e905a9eda   YOSHIFUJI Hideaki   [NET] IPV4: Fix w...
36

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
37
38
39
40
41
42
  	Minor tweaks:
  		Cleaned up the code a little and added some pre-1.3.0 tweaks.
  		dev->hard_header/hard_header_len changed to use no headers.
  		Comments/bracketing tweaked.
  		Made the tunnels use dev->name not tunnel: when error reporting.
  		Added tx_dropped stat
e905a9eda   YOSHIFUJI Hideaki   [NET] IPV4: Fix w...
43

113aa838e   Alan Cox   net: Rationalise ...
44
  		-Alan Cox	(alan@lxorguk.ukuu.org.uk) 21 March 95
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
45
46
47
48
49
50
51
52
  
  	Reworked:
  		Changed to tunnel to destination gateway in addition to the
  			tunnel's pointopoint address
  		Almost completely rewritten
  		Note:  There is currently no firewall or ICMP handling done.
  
  		-Sam Lantinga	(slouken@cs.ucdavis.edu) 02/13/96
e905a9eda   YOSHIFUJI Hideaki   [NET] IPV4: Fix w...
53

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
  */
  
  /* Things I wish I had known when writing the tunnel driver:
  
  	When the tunnel_xmit() function is called, the skb contains the
  	packet to be sent (plus a great deal of extra info), and dev
  	contains the tunnel device that _we_ are.
  
  	When we are passed a packet, we are expected to fill in the
  	source address with our source IP address.
  
  	What is the proper way to allocate, copy and free a buffer?
  	After you allocate it, it is a "0 length" chunk of memory
  	starting at zero.  If you want to add headers to the buffer
  	later, you'll have to call "skb_reserve(skb, amount)" with
  	the amount of memory you want reserved.  Then, you call
  	"skb_put(skb, amount)" with the amount of space you want in
  	the buffer.  skb_put() returns a pointer to the top (#0) of
  	that buffer.  skb->len is set to the amount of space you have
  	"allocated" with skb_put().  You can then write up to skb->len
  	bytes to that buffer.  If you need more, you can call skb_put()
  	again with the additional amount of space you need.  You can
e905a9eda   YOSHIFUJI Hideaki   [NET] IPV4: Fix w...
76
  	find out how much more space you can allocate by calling
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
  	"skb_tailroom(skb)".
  	Now, to add header space, call "skb_push(skb, header_len)".
  	This creates space at the beginning of the buffer and returns
  	a pointer to this new space.  If later you need to strip a
  	header from a buffer, call "skb_pull(skb, header_len)".
  	skb_headroom() will return how much space is left at the top
  	of the buffer (before the main data).  Remember, this headroom
  	space must be reserved before the skb_put() function is called.
  	*/
  
  /*
     This version of net/ipv4/ipip.c is cloned of net/ipv4/ip_gre.c
  
     For comments look at net/ipv4/ip_gre.c --ANK
   */
e905a9eda   YOSHIFUJI Hideaki   [NET] IPV4: Fix w...
92

4fc268d24   Randy Dunlap   [PATCH] capable/c...
93
  #include <linux/capability.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
94
95
  #include <linux/module.h>
  #include <linux/types.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
96
  #include <linux/kernel.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
97
  #include <linux/slab.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
98
99
100
101
102
103
104
  #include <asm/uaccess.h>
  #include <linux/skbuff.h>
  #include <linux/netdevice.h>
  #include <linux/in.h>
  #include <linux/tcp.h>
  #include <linux/udp.h>
  #include <linux/if_arp.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
105
106
  #include <linux/init.h>
  #include <linux/netfilter_ipv4.h>
46f25dffb   Kris Katterjohn   [NET]: Change 150...
107
  #include <linux/if_ether.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
108
109
110
111
  
  #include <net/sock.h>
  #include <net/ip.h>
  #include <net/icmp.h>
c54419321   Pravin B Shelar   GRE: Refactor GRE...
112
  #include <net/ip_tunnels.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
113
114
  #include <net/inet_ecn.h>
  #include <net/xfrm.h>
10dc4c7bb   Pavel Emelyanov   [IPIP]: Introduce...
115
116
  #include <net/net_namespace.h>
  #include <net/netns/generic.h>
cfc7381b3   Alexei Starovoitov   ip_tunnel: add co...
117
  #include <net/dst_metadata.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
118

eccc1bb8d   stephen hemminger   tunnel: drop pack...
119
120
121
  static bool log_ecn_error = true;
  module_param(log_ecn_error, bool, 0644);
  MODULE_PARM_DESC(log_ecn_error, "Log packets received with corrupted ECN");
f99189b18   Eric Dumazet   netns: net_identi...
122
  static int ipip_net_id __read_mostly;
10dc4c7bb   Pavel Emelyanov   [IPIP]: Introduce...
123

3c97af99a   Eric Dumazet   ipip: percpu stat...
124
  static int ipip_tunnel_init(struct net_device *dev);
0974658da   Nicolas Dichtel   ipip: advertise t...
125
  static struct rtnl_link_ops ipip_link_ops __read_mostly;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
126

d2acc3479   Herbert Xu   [INET]: Introduce...
127
  static int ipip_err(struct sk_buff *skb, u32 info)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
128
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
129

071f92d05   Rami Rosen   net: The world is...
130
  /* All the routers (except for Linux) return only
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
131
132
133
     8 bytes of packet payload. It means, that precise relaying of
     ICMP in the real Internet is absolutely infeasible.
   */
fd58156e4   Pravin B Shelar   IPIP: Use ip-tunn...
134
135
  	struct net *net = dev_net(skb->dev);
  	struct ip_tunnel_net *itn = net_generic(net, ipip_net_id);
b71d1d426   Eric Dumazet   inet: constify ip...
136
  	const struct iphdr *iph = (const struct iphdr *)skb->data;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
137
  	struct ip_tunnel *t;
d2acc3479   Herbert Xu   [INET]: Introduce...
138
  	int err;
fd58156e4   Pravin B Shelar   IPIP: Use ip-tunn...
139
140
  	const int type = icmp_hdr(skb)->type;
  	const int code = icmp_hdr(skb)->code;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
141

d2acc3479   Herbert Xu   [INET]: Introduce...
142
  	err = -ENOENT;
fd58156e4   Pravin B Shelar   IPIP: Use ip-tunn...
143
144
  	t = ip_tunnel_lookup(itn, skb->dev->ifindex, TUNNEL_NO_KEY,
  			     iph->daddr, iph->saddr, 0);
51456b291   Ian Morris   ipv4: coding styl...
145
  	if (!t)
363933955   David S. Miller   ipv4: Handle PMTU...
146
147
148
149
  		goto out;
  
  	if (type == ICMP_DEST_UNREACH && code == ICMP_FRAG_NEEDED) {
  		ipv4_update_pmtu(skb, dev_net(skb->dev), info,
1b69e7e6c   Simon Horman   ipip: support MPL...
150
  				 t->parms.link, 0, iph->protocol, 0);
363933955   David S. Miller   ipv4: Handle PMTU...
151
152
153
  		err = 0;
  		goto out;
  	}
55be7a9c6   David S. Miller   ipv4: Add redirec...
154
  	if (type == ICMP_REDIRECT) {
2346829e6   Dmitry Popov   ipip, sit: fix ip...
155
  		ipv4_redirect(skb, dev_net(skb->dev), t->parms.link, 0,
1b69e7e6c   Simon Horman   ipip: support MPL...
156
  			      iph->protocol, 0);
55be7a9c6   David S. Miller   ipv4: Add redirec...
157
158
159
  		err = 0;
  		goto out;
  	}
363933955   David S. Miller   ipv4: Handle PMTU...
160
  	if (t->parms.iph.daddr == 0)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
161
  		goto out;
d2acc3479   Herbert Xu   [INET]: Introduce...
162
163
  
  	err = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
164
165
  	if (t->parms.iph.ttl == 0 && type == ICMP_TIME_EXCEEDED)
  		goto out;
26d94b46d   Wei Yongjun   ipip: used time_b...
166
  	if (time_before(jiffies, t->err_time + IPTUNNEL_ERR_TIMEO))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
167
168
169
170
  		t->err_count++;
  	else
  		t->err_count = 1;
  	t->err_time = jiffies;
b0558ef24   stephen hemminger   xfrm: remove extr...
171

fd58156e4   Pravin B Shelar   IPIP: Use ip-tunn...
172
  out:
d2acc3479   Herbert Xu   [INET]: Introduce...
173
  	return err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
174
  }
1b69e7e6c   Simon Horman   ipip: support MPL...
175
  static const struct tnl_ptk_info ipip_tpi = {
fd58156e4   Pravin B Shelar   IPIP: Use ip-tunn...
176
177
178
  	/* no tunnel info required for ipip. */
  	.proto = htons(ETH_P_IP),
  };
1b69e7e6c   Simon Horman   ipip: support MPL...
179
180
181
182
183
184
185
186
  #if IS_ENABLED(CONFIG_MPLS)
  static const struct tnl_ptk_info mplsip_tpi = {
  	/* no tunnel info required for mplsip. */
  	.proto = htons(ETH_P_MPLS_UC),
  };
  #endif
  
  static int ipip_tunnel_rcv(struct sk_buff *skb, u8 ipproto)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
187
  {
fd58156e4   Pravin B Shelar   IPIP: Use ip-tunn...
188
189
  	struct net *net = dev_net(skb->dev);
  	struct ip_tunnel_net *itn = net_generic(net, ipip_net_id);
cfc7381b3   Alexei Starovoitov   ip_tunnel: add co...
190
  	struct metadata_dst *tun_dst = NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
191
  	struct ip_tunnel *tunnel;
3d7b46cd2   Pravin B Shelar   ip_tunnel: push g...
192
  	const struct iphdr *iph;
3c97af99a   Eric Dumazet   ipip: percpu stat...
193

3d7b46cd2   Pravin B Shelar   ip_tunnel: push g...
194
  	iph = ip_hdr(skb);
fd58156e4   Pravin B Shelar   IPIP: Use ip-tunn...
195
196
197
  	tunnel = ip_tunnel_lookup(itn, skb->dev->ifindex, TUNNEL_NO_KEY,
  			iph->saddr, iph->daddr, 0);
  	if (tunnel) {
1b69e7e6c   Simon Horman   ipip: support MPL...
198
199
200
201
202
  		const struct tnl_ptk_info *tpi;
  
  		if (tunnel->parms.iph.protocol != ipproto &&
  		    tunnel->parms.iph.protocol != 0)
  			goto drop;
eccc1bb8d   stephen hemminger   tunnel: drop pack...
203
204
  		if (!xfrm4_policy_check(NULL, XFRM_POLICY_IN, skb))
  			goto drop;
1b69e7e6c   Simon Horman   ipip: support MPL...
205
206
207
208
209
210
211
  #if IS_ENABLED(CONFIG_MPLS)
  		if (ipproto == IPPROTO_MPLS)
  			tpi = &mplsip_tpi;
  		else
  #endif
  			tpi = &ipip_tpi;
  		if (iptunnel_pull_header(skb, 0, tpi->proto, false))
737e828bd   Li Hongjun   ipv4 tunnels: fix...
212
  			goto drop;
cfc7381b3   Alexei Starovoitov   ip_tunnel: add co...
213
214
215
216
217
218
  		if (tunnel->collect_md) {
  			tun_dst = ip_tun_rx_dst(skb, 0, 0, 0);
  			if (!tun_dst)
  				return 0;
  		}
  		return ip_tunnel_rcv(tunnel, skb, tpi, tun_dst, log_ecn_error);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
219
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
220

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
221
  	return -1;
eccc1bb8d   stephen hemminger   tunnel: drop pack...
222
223
224
225
  
  drop:
  	kfree_skb(skb);
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
226
  }
1b69e7e6c   Simon Horman   ipip: support MPL...
227
228
229
230
231
232
233
234
235
236
237
  static int ipip_rcv(struct sk_buff *skb)
  {
  	return ipip_tunnel_rcv(skb, IPPROTO_IPIP);
  }
  
  #if IS_ENABLED(CONFIG_MPLS)
  static int mplsip_rcv(struct sk_buff *skb)
  {
  	return ipip_tunnel_rcv(skb, IPPROTO_MPLS);
  }
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
238
239
240
241
  /*
   *	This function assumes it is being called from dev_queue_xmit()
   *	and that skb is filled properly by that function.
   */
1b69e7e6c   Simon Horman   ipip: support MPL...
242
243
  static netdev_tx_t ipip_tunnel_xmit(struct sk_buff *skb,
  				    struct net_device *dev)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
244
  {
2941a4863   Patrick McHardy   [NET]: Convert ne...
245
  	struct ip_tunnel *tunnel = netdev_priv(dev);
b71d1d426   Eric Dumazet   inet: constify ip...
246
  	const struct iphdr  *tiph = &tunnel->parms.iph;
1b69e7e6c   Simon Horman   ipip: support MPL...
247
248
249
250
251
252
253
254
255
256
257
258
259
260
  	u8 ipproto;
  
  	switch (skb->protocol) {
  	case htons(ETH_P_IP):
  		ipproto = IPPROTO_IPIP;
  		break;
  #if IS_ENABLED(CONFIG_MPLS)
  	case htons(ETH_P_MPLS_UC):
  		ipproto = IPPROTO_MPLS;
  		break;
  #endif
  	default:
  		goto tx_error;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
261

1b69e7e6c   Simon Horman   ipip: support MPL...
262
  	if (tiph->protocol != ipproto && tiph->protocol != 0)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
263
  		goto tx_error;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
264

7e13318da   Tom Herbert   net: define gso t...
265
  	if (iptunnel_handle_offloads(skb, SKB_GSO_IPXIP4))
aed069df0   Alexander Duyck   ip_tunnel_core: i...
266
  		goto tx_error;
8344bfc60   Pravin B Shelar   ipip: Use tunnel_...
267

1b69e7e6c   Simon Horman   ipip: support MPL...
268
  	skb_set_inner_ipproto(skb, ipproto);
077c5a094   Tom Herbert   ipip: Set inner I...
269

cfc7381b3   Alexei Starovoitov   ip_tunnel: add co...
270
271
272
273
  	if (tunnel->collect_md)
  		ip_md_tunnel_xmit(skb, dev, ipproto);
  	else
  		ip_tunnel_xmit(skb, dev, tiph, ipproto);
6ed106549   Patrick McHardy   net: use NETDEV_T...
274
  	return NETDEV_TX_OK;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
275

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
276
  tx_error:
3acfa1e73   Eric Dumazet   ipv4: be friend w...
277
  	kfree_skb(skb);
aed069df0   Alexander Duyck   ip_tunnel_core: i...
278

cb32f511a   Eric Dumazet   ipip: add GSO/TSO...
279
  	dev->stats.tx_errors++;
6ed106549   Patrick McHardy   net: use NETDEV_T...
280
  	return NETDEV_TX_OK;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
281
  }
1b69e7e6c   Simon Horman   ipip: support MPL...
282
283
284
285
286
287
288
289
290
291
292
293
294
  static bool ipip_tunnel_ioctl_verify_protocol(u8 ipproto)
  {
  	switch (ipproto) {
  	case 0:
  	case IPPROTO_IPIP:
  #if IS_ENABLED(CONFIG_MPLS)
  	case IPPROTO_MPLS:
  #endif
  		return true;
  	}
  
  	return false;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
295
  static int
fd58156e4   Pravin B Shelar   IPIP: Use ip-tunn...
296
  ipip_tunnel_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
297
298
299
  {
  	int err = 0;
  	struct ip_tunnel_parm p;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
300

fd58156e4   Pravin B Shelar   IPIP: Use ip-tunn...
301
302
  	if (copy_from_user(&p, ifr->ifr_ifru.ifru_data, sizeof(p)))
  		return -EFAULT;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
303

3b7b514f4   Cong Wang   ipip: fix a regre...
304
  	if (cmd == SIOCADDTUNNEL || cmd == SIOCCHGTUNNEL) {
1b69e7e6c   Simon Horman   ipip: support MPL...
305
306
  		if (p.iph.version != 4 ||
  		    !ipip_tunnel_ioctl_verify_protocol(p.iph.protocol) ||
3b7b514f4   Cong Wang   ipip: fix a regre...
307
308
309
  		    p.iph.ihl != 5 || (p.iph.frag_off&htons(~IP_DF)))
  			return -EINVAL;
  	}
252a8fbe8   Eric Dumazet   ipip: fix one spa...
310
311
  	p.i_key = p.o_key = 0;
  	p.i_flags = p.o_flags = 0;
fd58156e4   Pravin B Shelar   IPIP: Use ip-tunn...
312
313
314
315
316
317
  	err = ip_tunnel_ioctl(dev, &p, cmd);
  	if (err)
  		return err;
  
  	if (copy_to_user(ifr->ifr_ifru.ifru_data, &p, sizeof(p)))
  		return -EFAULT;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
318
319
  	return 0;
  }
23a12b147   Stephen Hemminger   ipip: convert to ...
320
  static const struct net_device_ops ipip_netdev_ops = {
fd58156e4   Pravin B Shelar   IPIP: Use ip-tunn...
321
322
  	.ndo_init       = ipip_tunnel_init,
  	.ndo_uninit     = ip_tunnel_uninit,
23a12b147   Stephen Hemminger   ipip: convert to ...
323
324
  	.ndo_start_xmit	= ipip_tunnel_xmit,
  	.ndo_do_ioctl	= ipip_tunnel_ioctl,
fd58156e4   Pravin B Shelar   IPIP: Use ip-tunn...
325
326
  	.ndo_change_mtu = ip_tunnel_change_mtu,
  	.ndo_get_stats64 = ip_tunnel_get_stats64,
1e99584b9   Nicolas Dichtel   ipip,gre,vti,sit:...
327
  	.ndo_get_iflink = ip_tunnel_get_iflink,
23a12b147   Stephen Hemminger   ipip: convert to ...
328
  };
c3b89fbba   Eric Dumazet   ipip: add GSO sup...
329
330
331
  #define IPIP_FEATURES (NETIF_F_SG |		\
  		       NETIF_F_FRAGLIST |	\
  		       NETIF_F_HIGHDMA |	\
cb32f511a   Eric Dumazet   ipip: add GSO/TSO...
332
  		       NETIF_F_GSO_SOFTWARE |	\
c3b89fbba   Eric Dumazet   ipip: add GSO sup...
333
  		       NETIF_F_HW_CSUM)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
334
335
  static void ipip_tunnel_setup(struct net_device *dev)
  {
23a12b147   Stephen Hemminger   ipip: convert to ...
336
  	dev->netdev_ops		= &ipip_netdev_ops;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
337
338
  
  	dev->type		= ARPHRD_TUNNEL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
339
  	dev->flags		= IFF_NOARP;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
340
  	dev->addr_len		= 4;
153f09433   Eric Dumazet   ipip: enable lock...
341
  	dev->features		|= NETIF_F_LLTX;
028758788   Eric Dumazet   net: better IFF_X...
342
  	netif_keep_dst(dev);
c3b89fbba   Eric Dumazet   ipip: add GSO sup...
343
344
345
  
  	dev->features		|= IPIP_FEATURES;
  	dev->hw_features	|= IPIP_FEATURES;
fd58156e4   Pravin B Shelar   IPIP: Use ip-tunn...
346
  	ip_tunnel_setup(dev, ipip_net_id);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
347
  }
3c97af99a   Eric Dumazet   ipip: percpu stat...
348
  static int ipip_tunnel_init(struct net_device *dev)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
349
  {
23a12b147   Stephen Hemminger   ipip: convert to ...
350
  	struct ip_tunnel *tunnel = netdev_priv(dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
351

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
352
353
  	memcpy(dev->dev_addr, &tunnel->parms.iph.saddr, 4);
  	memcpy(dev->broadcast, &tunnel->parms.iph.daddr, 4);
473ab820d   Tom Herbert   ipip: Setup and T...
354
355
  	tunnel->tun_hlen = 0;
  	tunnel->hlen = tunnel->tun_hlen + tunnel->encap_hlen;
fd58156e4   Pravin B Shelar   IPIP: Use ip-tunn...
356
  	return ip_tunnel_init(dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
357
  }
1b69e7e6c   Simon Horman   ipip: support MPL...
358
359
360
361
362
363
364
365
366
367
368
369
370
  static int ipip_tunnel_validate(struct nlattr *tb[], struct nlattr *data[])
  {
  	u8 proto;
  
  	if (!data || !data[IFLA_IPTUN_PROTO])
  		return 0;
  
  	proto = nla_get_u8(data[IFLA_IPTUN_PROTO]);
  	if (proto != IPPROTO_IPIP && proto != IPPROTO_MPLS && proto != 0)
  		return -EINVAL;
  
  	return 0;
  }
be42da0e1   Nicolas Dichtel   ipip: add support...
371
  static void ipip_netlink_parms(struct nlattr *data[],
cfc7381b3   Alexei Starovoitov   ip_tunnel: add co...
372
  			       struct ip_tunnel_parm *parms, bool *collect_md)
be42da0e1   Nicolas Dichtel   ipip: add support...
373
374
375
376
377
378
  {
  	memset(parms, 0, sizeof(*parms));
  
  	parms->iph.version = 4;
  	parms->iph.protocol = IPPROTO_IPIP;
  	parms->iph.ihl = 5;
cfc7381b3   Alexei Starovoitov   ip_tunnel: add co...
379
  	*collect_md = false;
be42da0e1   Nicolas Dichtel   ipip: add support...
380
381
382
383
384
385
386
387
  
  	if (!data)
  		return;
  
  	if (data[IFLA_IPTUN_LINK])
  		parms->link = nla_get_u32(data[IFLA_IPTUN_LINK]);
  
  	if (data[IFLA_IPTUN_LOCAL])
67b61f6c1   Jiri Benc   netlink: implemen...
388
  		parms->iph.saddr = nla_get_in_addr(data[IFLA_IPTUN_LOCAL]);
be42da0e1   Nicolas Dichtel   ipip: add support...
389
390
  
  	if (data[IFLA_IPTUN_REMOTE])
67b61f6c1   Jiri Benc   netlink: implemen...
391
  		parms->iph.daddr = nla_get_in_addr(data[IFLA_IPTUN_REMOTE]);
be42da0e1   Nicolas Dichtel   ipip: add support...
392
393
394
395
396
397
398
399
400
  
  	if (data[IFLA_IPTUN_TTL]) {
  		parms->iph.ttl = nla_get_u8(data[IFLA_IPTUN_TTL]);
  		if (parms->iph.ttl)
  			parms->iph.frag_off = htons(IP_DF);
  	}
  
  	if (data[IFLA_IPTUN_TOS])
  		parms->iph.tos = nla_get_u8(data[IFLA_IPTUN_TOS]);
1b69e7e6c   Simon Horman   ipip: support MPL...
401
402
  	if (data[IFLA_IPTUN_PROTO])
  		parms->iph.protocol = nla_get_u8(data[IFLA_IPTUN_PROTO]);
be42da0e1   Nicolas Dichtel   ipip: add support...
403
404
  	if (!data[IFLA_IPTUN_PMTUDISC] || nla_get_u8(data[IFLA_IPTUN_PMTUDISC]))
  		parms->iph.frag_off = htons(IP_DF);
cfc7381b3   Alexei Starovoitov   ip_tunnel: add co...
405
406
407
  
  	if (data[IFLA_IPTUN_COLLECT_METADATA])
  		*collect_md = true;
be42da0e1   Nicolas Dichtel   ipip: add support...
408
  }
473ab820d   Tom Herbert   ipip: Setup and T...
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
  /* This function returns true when ENCAP attributes are present in the nl msg */
  static bool ipip_netlink_encap_parms(struct nlattr *data[],
  				     struct ip_tunnel_encap *ipencap)
  {
  	bool ret = false;
  
  	memset(ipencap, 0, sizeof(*ipencap));
  
  	if (!data)
  		return ret;
  
  	if (data[IFLA_IPTUN_ENCAP_TYPE]) {
  		ret = true;
  		ipencap->type = nla_get_u16(data[IFLA_IPTUN_ENCAP_TYPE]);
  	}
  
  	if (data[IFLA_IPTUN_ENCAP_FLAGS]) {
  		ret = true;
  		ipencap->flags = nla_get_u16(data[IFLA_IPTUN_ENCAP_FLAGS]);
  	}
  
  	if (data[IFLA_IPTUN_ENCAP_SPORT]) {
  		ret = true;
3e97fa705   Sabrina Dubroca   gre/ipip: use be1...
432
  		ipencap->sport = nla_get_be16(data[IFLA_IPTUN_ENCAP_SPORT]);
473ab820d   Tom Herbert   ipip: Setup and T...
433
434
435
436
  	}
  
  	if (data[IFLA_IPTUN_ENCAP_DPORT]) {
  		ret = true;
3e97fa705   Sabrina Dubroca   gre/ipip: use be1...
437
  		ipencap->dport = nla_get_be16(data[IFLA_IPTUN_ENCAP_DPORT]);
473ab820d   Tom Herbert   ipip: Setup and T...
438
439
440
441
  	}
  
  	return ret;
  }
be42da0e1   Nicolas Dichtel   ipip: add support...
442
443
444
  static int ipip_newlink(struct net *src_net, struct net_device *dev,
  			struct nlattr *tb[], struct nlattr *data[])
  {
cfc7381b3   Alexei Starovoitov   ip_tunnel: add co...
445
  	struct ip_tunnel *t = netdev_priv(dev);
fd58156e4   Pravin B Shelar   IPIP: Use ip-tunn...
446
  	struct ip_tunnel_parm p;
473ab820d   Tom Herbert   ipip: Setup and T...
447
448
449
  	struct ip_tunnel_encap ipencap;
  
  	if (ipip_netlink_encap_parms(data, &ipencap)) {
473ab820d   Tom Herbert   ipip: Setup and T...
450
451
452
453
454
  		int err = ip_tunnel_encap_setup(t, &ipencap);
  
  		if (err < 0)
  			return err;
  	}
be42da0e1   Nicolas Dichtel   ipip: add support...
455

cfc7381b3   Alexei Starovoitov   ip_tunnel: add co...
456
  	ipip_netlink_parms(data, &p, &t->collect_md);
fd58156e4   Pravin B Shelar   IPIP: Use ip-tunn...
457
  	return ip_tunnel_newlink(dev, tb, &p);
be42da0e1   Nicolas Dichtel   ipip: add support...
458
459
460
461
462
  }
  
  static int ipip_changelink(struct net_device *dev, struct nlattr *tb[],
  			   struct nlattr *data[])
  {
be42da0e1   Nicolas Dichtel   ipip: add support...
463
  	struct ip_tunnel_parm p;
473ab820d   Tom Herbert   ipip: Setup and T...
464
  	struct ip_tunnel_encap ipencap;
cfc7381b3   Alexei Starovoitov   ip_tunnel: add co...
465
  	bool collect_md;
473ab820d   Tom Herbert   ipip: Setup and T...
466
467
468
469
470
471
472
473
  
  	if (ipip_netlink_encap_parms(data, &ipencap)) {
  		struct ip_tunnel *t = netdev_priv(dev);
  		int err = ip_tunnel_encap_setup(t, &ipencap);
  
  		if (err < 0)
  			return err;
  	}
be42da0e1   Nicolas Dichtel   ipip: add support...
474

cfc7381b3   Alexei Starovoitov   ip_tunnel: add co...
475
476
477
  	ipip_netlink_parms(data, &p, &collect_md);
  	if (collect_md)
  		return -EINVAL;
be42da0e1   Nicolas Dichtel   ipip: add support...
478
479
480
481
  
  	if (((dev->flags & IFF_POINTOPOINT) && !p.iph.daddr) ||
  	    (!(dev->flags & IFF_POINTOPOINT) && p.iph.daddr))
  		return -EINVAL;
fd58156e4   Pravin B Shelar   IPIP: Use ip-tunn...
482
  	return ip_tunnel_changelink(dev, tb, &p);
be42da0e1   Nicolas Dichtel   ipip: add support...
483
  }
0974658da   Nicolas Dichtel   ipip: advertise t...
484
485
486
487
488
489
490
491
492
493
494
495
496
  static size_t ipip_get_size(const struct net_device *dev)
  {
  	return
  		/* IFLA_IPTUN_LINK */
  		nla_total_size(4) +
  		/* IFLA_IPTUN_LOCAL */
  		nla_total_size(4) +
  		/* IFLA_IPTUN_REMOTE */
  		nla_total_size(4) +
  		/* IFLA_IPTUN_TTL */
  		nla_total_size(1) +
  		/* IFLA_IPTUN_TOS */
  		nla_total_size(1) +
1b69e7e6c   Simon Horman   ipip: support MPL...
497
498
  		/* IFLA_IPTUN_PROTO */
  		nla_total_size(1) +
befe2aa1b   Nicolas Dichtel   ipip/rtnl: add IF...
499
500
  		/* IFLA_IPTUN_PMTUDISC */
  		nla_total_size(1) +
473ab820d   Tom Herbert   ipip: Setup and T...
501
502
503
504
505
506
507
508
  		/* IFLA_IPTUN_ENCAP_TYPE */
  		nla_total_size(2) +
  		/* IFLA_IPTUN_ENCAP_FLAGS */
  		nla_total_size(2) +
  		/* IFLA_IPTUN_ENCAP_SPORT */
  		nla_total_size(2) +
  		/* IFLA_IPTUN_ENCAP_DPORT */
  		nla_total_size(2) +
cfc7381b3   Alexei Starovoitov   ip_tunnel: add co...
509
510
  		/* IFLA_IPTUN_COLLECT_METADATA */
  		nla_total_size(0) +
0974658da   Nicolas Dichtel   ipip: advertise t...
511
512
513
514
515
516
517
518
519
  		0;
  }
  
  static int ipip_fill_info(struct sk_buff *skb, const struct net_device *dev)
  {
  	struct ip_tunnel *tunnel = netdev_priv(dev);
  	struct ip_tunnel_parm *parm = &tunnel->parms;
  
  	if (nla_put_u32(skb, IFLA_IPTUN_LINK, parm->link) ||
930345ea6   Jiri Benc   netlink: implemen...
520
521
  	    nla_put_in_addr(skb, IFLA_IPTUN_LOCAL, parm->iph.saddr) ||
  	    nla_put_in_addr(skb, IFLA_IPTUN_REMOTE, parm->iph.daddr) ||
0974658da   Nicolas Dichtel   ipip: advertise t...
522
  	    nla_put_u8(skb, IFLA_IPTUN_TTL, parm->iph.ttl) ||
befe2aa1b   Nicolas Dichtel   ipip/rtnl: add IF...
523
  	    nla_put_u8(skb, IFLA_IPTUN_TOS, parm->iph.tos) ||
1b69e7e6c   Simon Horman   ipip: support MPL...
524
  	    nla_put_u8(skb, IFLA_IPTUN_PROTO, parm->iph.protocol) ||
befe2aa1b   Nicolas Dichtel   ipip/rtnl: add IF...
525
526
  	    nla_put_u8(skb, IFLA_IPTUN_PMTUDISC,
  		       !!(parm->iph.frag_off & htons(IP_DF))))
0974658da   Nicolas Dichtel   ipip: advertise t...
527
  		goto nla_put_failure;
473ab820d   Tom Herbert   ipip: Setup and T...
528
529
530
  
  	if (nla_put_u16(skb, IFLA_IPTUN_ENCAP_TYPE,
  			tunnel->encap.type) ||
3e97fa705   Sabrina Dubroca   gre/ipip: use be1...
531
532
533
534
  	    nla_put_be16(skb, IFLA_IPTUN_ENCAP_SPORT,
  			 tunnel->encap.sport) ||
  	    nla_put_be16(skb, IFLA_IPTUN_ENCAP_DPORT,
  			 tunnel->encap.dport) ||
473ab820d   Tom Herbert   ipip: Setup and T...
535
  	    nla_put_u16(skb, IFLA_IPTUN_ENCAP_FLAGS,
e1b2cb655   Tom Herbert   fou: Fix typo in ...
536
  			tunnel->encap.flags))
473ab820d   Tom Herbert   ipip: Setup and T...
537
  		goto nla_put_failure;
cfc7381b3   Alexei Starovoitov   ip_tunnel: add co...
538
539
540
  	if (tunnel->collect_md)
  		if (nla_put_flag(skb, IFLA_IPTUN_COLLECT_METADATA))
  			goto nla_put_failure;
0974658da   Nicolas Dichtel   ipip: advertise t...
541
542
543
544
545
  	return 0;
  
  nla_put_failure:
  	return -EMSGSIZE;
  }
be42da0e1   Nicolas Dichtel   ipip: add support...
546
547
548
549
550
551
  static const struct nla_policy ipip_policy[IFLA_IPTUN_MAX + 1] = {
  	[IFLA_IPTUN_LINK]		= { .type = NLA_U32 },
  	[IFLA_IPTUN_LOCAL]		= { .type = NLA_U32 },
  	[IFLA_IPTUN_REMOTE]		= { .type = NLA_U32 },
  	[IFLA_IPTUN_TTL]		= { .type = NLA_U8 },
  	[IFLA_IPTUN_TOS]		= { .type = NLA_U8 },
1b69e7e6c   Simon Horman   ipip: support MPL...
552
  	[IFLA_IPTUN_PROTO]		= { .type = NLA_U8 },
be42da0e1   Nicolas Dichtel   ipip: add support...
553
  	[IFLA_IPTUN_PMTUDISC]		= { .type = NLA_U8 },
473ab820d   Tom Herbert   ipip: Setup and T...
554
555
556
557
  	[IFLA_IPTUN_ENCAP_TYPE]		= { .type = NLA_U16 },
  	[IFLA_IPTUN_ENCAP_FLAGS]	= { .type = NLA_U16 },
  	[IFLA_IPTUN_ENCAP_SPORT]	= { .type = NLA_U16 },
  	[IFLA_IPTUN_ENCAP_DPORT]	= { .type = NLA_U16 },
cfc7381b3   Alexei Starovoitov   ip_tunnel: add co...
558
  	[IFLA_IPTUN_COLLECT_METADATA]	= { .type = NLA_FLAG },
be42da0e1   Nicolas Dichtel   ipip: add support...
559
  };
0974658da   Nicolas Dichtel   ipip: advertise t...
560
561
562
  static struct rtnl_link_ops ipip_link_ops __read_mostly = {
  	.kind		= "ipip",
  	.maxtype	= IFLA_IPTUN_MAX,
be42da0e1   Nicolas Dichtel   ipip: add support...
563
  	.policy		= ipip_policy,
0974658da   Nicolas Dichtel   ipip: advertise t...
564
  	.priv_size	= sizeof(struct ip_tunnel),
be42da0e1   Nicolas Dichtel   ipip: add support...
565
  	.setup		= ipip_tunnel_setup,
1b69e7e6c   Simon Horman   ipip: support MPL...
566
  	.validate	= ipip_tunnel_validate,
be42da0e1   Nicolas Dichtel   ipip: add support...
567
568
  	.newlink	= ipip_newlink,
  	.changelink	= ipip_changelink,
fd58156e4   Pravin B Shelar   IPIP: Use ip-tunn...
569
  	.dellink	= ip_tunnel_dellink,
0974658da   Nicolas Dichtel   ipip: advertise t...
570
571
  	.get_size	= ipip_get_size,
  	.fill_info	= ipip_fill_info,
1728d4fab   Nicolas Dichtel   tunnels: advertis...
572
  	.get_link_net	= ip_tunnel_get_link_net,
0974658da   Nicolas Dichtel   ipip: advertise t...
573
  };
6dcd814bd   Eric Dumazet   net: struct xfrm_...
574
  static struct xfrm_tunnel ipip_handler __read_mostly = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
575
576
  	.handler	=	ipip_rcv,
  	.err_handler	=	ipip_err,
d2acc3479   Herbert Xu   [INET]: Introduce...
577
  	.priority	=	1,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
578
  };
1b69e7e6c   Simon Horman   ipip: support MPL...
579
580
581
582
583
584
585
  #if IS_ENABLED(CONFIG_MPLS)
  static struct xfrm_tunnel mplsip_handler __read_mostly = {
  	.handler	=	mplsip_rcv,
  	.err_handler	=	ipip_err,
  	.priority	=	1,
  };
  #endif
2c8c1e729   Alexey Dobriyan   net: spread __net...
586
  static int __net_init ipip_init_net(struct net *net)
10dc4c7bb   Pavel Emelyanov   [IPIP]: Introduce...
587
  {
fd58156e4   Pravin B Shelar   IPIP: Use ip-tunn...
588
  	return ip_tunnel_init_net(net, ipip_net_id, &ipip_link_ops, "tunl0");
10dc4c7bb   Pavel Emelyanov   [IPIP]: Introduce...
589
  }
2c8c1e729   Alexey Dobriyan   net: spread __net...
590
  static void __net_exit ipip_exit_net(struct net *net)
10dc4c7bb   Pavel Emelyanov   [IPIP]: Introduce...
591
  {
fd58156e4   Pravin B Shelar   IPIP: Use ip-tunn...
592
  	struct ip_tunnel_net *itn = net_generic(net, ipip_net_id);
6c742e714   Nicolas Dichtel   ipip: add x-netns...
593
  	ip_tunnel_delete_net(itn, &ipip_link_ops);
10dc4c7bb   Pavel Emelyanov   [IPIP]: Introduce...
594
595
596
597
598
  }
  
  static struct pernet_operations ipip_net_ops = {
  	.init = ipip_init_net,
  	.exit = ipip_exit_net,
86de8a631   Eric W. Biederman   net: Simplify ipi...
599
  	.id   = &ipip_net_id,
fd58156e4   Pravin B Shelar   IPIP: Use ip-tunn...
600
  	.size = sizeof(struct ip_tunnel_net),
10dc4c7bb   Pavel Emelyanov   [IPIP]: Introduce...
601
  };
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
602
603
604
  static int __init ipip_init(void)
  {
  	int err;
1b69e7e6c   Simon Horman   ipip: support MPL...
605
606
  	pr_info("ipip: IPv4 and MPLS over IPv4 tunneling driver
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
607

d5aa407f5   Alexey Dobriyan   tunnels: fix netn...
608
609
610
611
612
  	err = register_pernet_device(&ipip_net_ops);
  	if (err < 0)
  		return err;
  	err = xfrm4_tunnel_register(&ipip_handler, AF_INET);
  	if (err < 0) {
058bd4d2a   Joe Perches   net: Convert prin...
613
614
  		pr_info("%s: can't register tunnel
  ", __func__);
1b69e7e6c   Simon Horman   ipip: support MPL...
615
616
617
618
619
620
621
622
  		goto xfrm_tunnel_ipip_failed;
  	}
  #if IS_ENABLED(CONFIG_MPLS)
  	err = xfrm4_tunnel_register(&mplsip_handler, AF_MPLS);
  	if (err < 0) {
  		pr_info("%s: can't register tunnel
  ", __func__);
  		goto xfrm_tunnel_mplsip_failed;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
623
  	}
1b69e7e6c   Simon Horman   ipip: support MPL...
624
  #endif
0974658da   Nicolas Dichtel   ipip: advertise t...
625
626
627
628
629
  	err = rtnl_link_register(&ipip_link_ops);
  	if (err < 0)
  		goto rtnl_link_failed;
  
  out:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
630
  	return err;
0974658da   Nicolas Dichtel   ipip: advertise t...
631
632
  
  rtnl_link_failed:
1b69e7e6c   Simon Horman   ipip: support MPL...
633
634
635
636
637
  #if IS_ENABLED(CONFIG_MPLS)
  	xfrm4_tunnel_deregister(&mplsip_handler, AF_INET);
  xfrm_tunnel_mplsip_failed:
  
  #endif
0974658da   Nicolas Dichtel   ipip: advertise t...
638
  	xfrm4_tunnel_deregister(&ipip_handler, AF_INET);
1b69e7e6c   Simon Horman   ipip: support MPL...
639
  xfrm_tunnel_ipip_failed:
0974658da   Nicolas Dichtel   ipip: advertise t...
640
641
  	unregister_pernet_device(&ipip_net_ops);
  	goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
642
643
644
645
  }
  
  static void __exit ipip_fini(void)
  {
0974658da   Nicolas Dichtel   ipip: advertise t...
646
  	rtnl_link_unregister(&ipip_link_ops);
c0d56408e   Kazunori MIYAZAWA   [IPSEC]: Changing...
647
  	if (xfrm4_tunnel_deregister(&ipip_handler, AF_INET))
058bd4d2a   Joe Perches   net: Convert prin...
648
649
  		pr_info("%s: can't deregister tunnel
  ", __func__);
1b69e7e6c   Simon Horman   ipip: support MPL...
650
651
652
653
654
  #if IS_ENABLED(CONFIG_MPLS)
  	if (xfrm4_tunnel_deregister(&mplsip_handler, AF_MPLS))
  		pr_info("%s: can't deregister tunnel
  ", __func__);
  #endif
86de8a631   Eric W. Biederman   net: Simplify ipi...
655
  	unregister_pernet_device(&ipip_net_ops);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
656
657
658
659
660
  }
  
  module_init(ipip_init);
  module_exit(ipip_fini);
  MODULE_LICENSE("GPL");
f98f89a01   Tom Gundersen   net: tunnels - en...
661
  MODULE_ALIAS_RTNL_LINK("ipip");
8909c9ad8   Vasiliy Kulikov   net: don't allow ...
662
  MODULE_ALIAS_NETDEV("tunl0");