Blame view

net/ipv4/icmp.c 28.7 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
2
3
  /*
   *	NET3:	Implementation of the ICMP protocol layer.
   *
113aa838e   Alan Cox   net: Rationalise ...
4
   *		Alan Cox, <alan@lxorguk.ukuu.org.uk>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
5
   *
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
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
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
   *	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.
   *
   *	Some of the function names and the icmp unreach table for this
   *	module were derived from [icmp.c 1.0.11 06/02/93] by
   *	Ross Biro, Fred N. van Kempen, Mark Evans, Alan Cox, Gerhard Koerting.
   *	Other than that this module is a complete rewrite.
   *
   *	Fixes:
   *	Clemens Fruhwirth	:	introduce global icmp rate limiting
   *					with icmp type masking ability instead
   *					of broken per type icmp timeouts.
   *		Mike Shaver	:	RFC1122 checks.
   *		Alan Cox	:	Multicast ping reply as self.
   *		Alan Cox	:	Fix atomicity lockup in ip_build_xmit
   *					call.
   *		Alan Cox	:	Added 216,128 byte paths to the MTU
   *					code.
   *		Martin Mares	:	RFC1812 checks.
   *		Martin Mares	:	Can be configured to follow redirects
   *					if acting as a router _without_ a
   *					routing protocol (RFC 1812).
   *		Martin Mares	:	Echo requests may be configured to
   *					be ignored (RFC 1812).
   *		Martin Mares	:	Limitation of ICMP error message
   *					transmit rate (RFC 1812).
   *		Martin Mares	:	TOS and Precedence set correctly
   *					(RFC 1812).
   *		Martin Mares	:	Now copying as much data from the
   *					original packet as we can without
   *					exceeding 576 bytes (RFC 1812).
   *	Willy Konynenberg	:	Transparent proxying support.
   *		Keith Owens	:	RFC1191 correction for 4.2BSD based
   *					path MTU bug.
   *		Thomas Quinot	:	ICMP Dest Unreach codes up to 15 are
   *					valid (RFC 1812).
   *		Andi Kleen	:	Check all packet lengths properly
   *					and moved all kfree_skb() up to
   *					icmp_rcv.
   *		Andi Kleen	:	Move the rate limit bookkeeping
   *					into the dest entry and use a token
   *					bucket filter (thanks to ANK). Make
   *					the rates sysctl configurable.
   *		Yu Tianli	:	Fixed two ugly bugs in icmp_send
   *					- IP option length was accounted wrongly
   *					- ICMP header length was not accounted
   *					  at all.
   *              Tristan Greaves :       Added sysctl option to ignore bogus
   *              			broadcast responses from broken routers.
   *
   * To Fix:
   *
   *	- Should use skb_pull() instead of all the manual checking.
   *	  This would also greatly simply some upper layer error handlers. --AK
   *
   */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
64
65
66
67
68
69
70
71
  #include <linux/module.h>
  #include <linux/types.h>
  #include <linux/jiffies.h>
  #include <linux/kernel.h>
  #include <linux/fcntl.h>
  #include <linux/socket.h>
  #include <linux/in.h>
  #include <linux/inet.h>
14c850212   Arnaldo Carvalho de Melo   [INET_SOCK]: Move...
72
  #include <linux/inetdevice.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
73
74
75
  #include <linux/netdevice.h>
  #include <linux/string.h>
  #include <linux/netfilter_ipv4.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
76
  #include <linux/slab.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
77
78
79
80
81
82
83
84
  #include <net/snmp.h>
  #include <net/ip.h>
  #include <net/route.h>
  #include <net/protocol.h>
  #include <net/icmp.h>
  #include <net/tcp.h>
  #include <net/udp.h>
  #include <net/raw.h>
c319b4d76   Vasiliy Kulikov   net: ipv4: add IP...
85
  #include <net/ping.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
86
87
88
89
90
91
92
93
  #include <linux/skbuff.h>
  #include <net/sock.h>
  #include <linux/errno.h>
  #include <linux/timer.h>
  #include <linux/init.h>
  #include <asm/system.h>
  #include <asm/uaccess.h>
  #include <net/checksum.h>
8b7817f3a   Herbert Xu   [IPSEC]: Add ICMP...
94
  #include <net/xfrm.h>
c1e9894d4   Denis V. Lunev   [ICMP]: Simplify ...
95
  #include <net/inet_common.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
96
97
98
99
100
101
102
103
104
105
106
107
  
  /*
   *	Build xmit assembly blocks
   */
  
  struct icmp_bxm {
  	struct sk_buff *skb;
  	int offset;
  	int data_len;
  
  	struct {
  		struct icmphdr icmph;
b03d73e30   Al Viro   [IPV4] net/ipv4/i...
108
  		__be32	       times[3];
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
109
110
  	} data;
  	int head_len;
f6d8bd051   Eric Dumazet   inet: add RCU pro...
111
  	struct ip_options_data replyopts;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
112
  };
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
113
114
  /* An array of errno for error messages from dest unreach. */
  /* RFC 1122: 3.2.2.1 States that NET_UNREACH, HOST_UNREACH and SR_FAILED MUST be considered 'transient errs'. */
e754834e6   Alexey Dobriyan   icmp: move icmp_e...
115
  const struct icmp_err icmp_err_convert[] = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
  	{
  		.errno = ENETUNREACH,	/* ICMP_NET_UNREACH */
  		.fatal = 0,
  	},
  	{
  		.errno = EHOSTUNREACH,	/* ICMP_HOST_UNREACH */
  		.fatal = 0,
  	},
  	{
  		.errno = ENOPROTOOPT	/* ICMP_PROT_UNREACH */,
  		.fatal = 1,
  	},
  	{
  		.errno = ECONNREFUSED,	/* ICMP_PORT_UNREACH */
  		.fatal = 1,
  	},
  	{
  		.errno = EMSGSIZE,	/* ICMP_FRAG_NEEDED */
  		.fatal = 0,
  	},
  	{
  		.errno = EOPNOTSUPP,	/* ICMP_SR_FAILED */
  		.fatal = 0,
  	},
  	{
  		.errno = ENETUNREACH,	/* ICMP_NET_UNKNOWN */
  		.fatal = 1,
  	},
  	{
  		.errno = EHOSTDOWN,	/* ICMP_HOST_UNKNOWN */
  		.fatal = 1,
  	},
  	{
  		.errno = ENONET,	/* ICMP_HOST_ISOLATED */
  		.fatal = 1,
  	},
  	{
  		.errno = ENETUNREACH,	/* ICMP_NET_ANO	*/
  		.fatal = 1,
  	},
  	{
  		.errno = EHOSTUNREACH,	/* ICMP_HOST_ANO */
  		.fatal = 1,
  	},
  	{
  		.errno = ENETUNREACH,	/* ICMP_NET_UNR_TOS */
  		.fatal = 0,
  	},
  	{
  		.errno = EHOSTUNREACH,	/* ICMP_HOST_UNR_TOS */
  		.fatal = 0,
  	},
  	{
  		.errno = EHOSTUNREACH,	/* ICMP_PKT_FILTERED */
  		.fatal = 1,
  	},
  	{
  		.errno = EHOSTUNREACH,	/* ICMP_PREC_VIOLATION */
  		.fatal = 1,
  	},
  	{
  		.errno = EHOSTUNREACH,	/* ICMP_PREC_CUTOFF */
  		.fatal = 1,
  	},
  };
4bc2f18ba   Eric Dumazet   net/ipv4: EXPORT_...
181
  EXPORT_SYMBOL(icmp_err_convert);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
182

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
183
184
185
186
187
  /*
   *	ICMP control array. This specifies what to do with each ICMP.
   */
  
  struct icmp_control {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
188
189
190
  	void (*handler)(struct sk_buff *skb);
  	short   error;		/* This ICMP is classed as an error message */
  };
9b5b5cff9   Arjan van de Ven   [NET]: Add const ...
191
  static const struct icmp_control icmp_pointers[NR_ICMP_TYPES+1];
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
192
193
194
195
196
197
198
199
  
  /*
   *	The ICMP socket(s). This is the most convenient way to flow control
   *	our ICMP output as well as maintain a clean interface throughout
   *	all layers. All Socketless IP sends will soon be gone.
   *
   *	On SMP we have one ICMP socket per-cpu.
   */
4a6ad7a14   Denis V. Lunev   [NETNS]: Make icm...
200
201
202
203
  static struct sock *icmp_sk(struct net *net)
  {
  	return net->ipv4.icmp_sk[smp_processor_id()];
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
204

fdc0bde90   Denis V. Lunev   icmp: icmp_sk() s...
205
  static inline struct sock *icmp_xmit_lock(struct net *net)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
206
  {
fdc0bde90   Denis V. Lunev   icmp: icmp_sk() s...
207
  	struct sock *sk;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
208
  	local_bh_disable();
fdc0bde90   Denis V. Lunev   icmp: icmp_sk() s...
209
  	sk = icmp_sk(net);
405666db8   Denis V. Lunev   [ICMP]: Pass prop...
210
  	if (unlikely(!spin_trylock(&sk->sk_lock.slock))) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
211
212
213
214
  		/* This can happen if the output path signals a
  		 * dst_link_failure() for an outgoing ICMP packet.
  		 */
  		local_bh_enable();
fdc0bde90   Denis V. Lunev   icmp: icmp_sk() s...
215
  		return NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
216
  	}
fdc0bde90   Denis V. Lunev   icmp: icmp_sk() s...
217
  	return sk;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
218
  }
405666db8   Denis V. Lunev   [ICMP]: Pass prop...
219
  static inline void icmp_xmit_unlock(struct sock *sk)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
220
  {
405666db8   Denis V. Lunev   [ICMP]: Pass prop...
221
  	spin_unlock_bh(&sk->sk_lock.slock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
222
223
224
225
226
  }
  
  /*
   *	Send an ICMP frame.
   */
92d868292   David S. Miller   inetpeer: Move IC...
227
  static inline bool icmpv4_xrlim_allow(struct net *net, struct rtable *rt,
a48eff128   David S. Miller   ipv4: Pass explic...
228
  				      struct flowi4 *fl4, int type, int code)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
229
  {
d8d1f30b9   Changli Gao   net-next: remove ...
230
  	struct dst_entry *dst = &rt->dst;
92d868292   David S. Miller   inetpeer: Move IC...
231
  	bool rc = true;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
232
233
234
235
236
237
238
239
240
241
  
  	if (type > NR_ICMP_TYPES)
  		goto out;
  
  	/* Don't limit PMTU discovery. */
  	if (type == ICMP_DEST_UNREACH && code == ICMP_FRAG_NEEDED)
  		goto out;
  
  	/* No rate limit on loopback */
  	if (dst->dev && (dst->dev->flags&IFF_LOOPBACK))
e905a9eda   YOSHIFUJI Hideaki   [NET] IPV4: Fix w...
242
  		goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
243
244
  
  	/* Limit if icmp type is enabled in ratemask. */
92d868292   David S. Miller   inetpeer: Move IC...
245
246
  	if ((1 << type) & net->ipv4.sysctl_icmp_ratemask) {
  		if (!rt->peer)
a48eff128   David S. Miller   ipv4: Pass explic...
247
  			rt_bind_peer(rt, fl4->daddr, 1);
92d868292   David S. Miller   inetpeer: Move IC...
248
249
250
  		rc = inet_peer_xrlim_allow(rt->peer,
  					   net->ipv4.sysctl_icmp_ratelimit);
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
251
252
253
254
255
256
257
  out:
  	return rc;
  }
  
  /*
   *	Maintain the counters used in the SNMP statistics for outgoing ICMP
   */
0388b0042   Pavel Emelyanov   icmp: add struct ...
258
  void icmp_out_count(struct net *net, unsigned char type)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
259
  {
903fc1964   Pavel Emelyanov   mib: add struct n...
260
  	ICMPMSGOUT_INC_STATS(net, type);
75c939bb4   Pavel Emelyanov   mib: add struct n...
261
  	ICMP_INC_STATS(net, ICMP_MIB_OUTMSGS);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
262
263
264
265
266
267
268
269
270
271
  }
  
  /*
   *	Checksum each fragment, and on the first include the headers and final
   *	checksum.
   */
  static int icmp_glue_bits(void *from, char *to, int offset, int len, int odd,
  			  struct sk_buff *skb)
  {
  	struct icmp_bxm *icmp_param = (struct icmp_bxm *)from;
5f92a7388   Al Viro   [NET]: Annotate c...
272
  	__wsum csum;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
273
274
275
276
277
278
279
280
281
282
283
284
  
  	csum = skb_copy_and_csum_bits(icmp_param->skb,
  				      icmp_param->offset + offset,
  				      to, len, 0);
  
  	skb->csum = csum_block_add(skb->csum, csum, odd);
  	if (icmp_pointers[icmp_param->data.icmph.type].error)
  		nf_ct_attach(skb, icmp_param->skb);
  	return 0;
  }
  
  static void icmp_push_reply(struct icmp_bxm *icmp_param,
77968b782   David S. Miller   ipv4: Pass flow k...
285
  			    struct flowi4 *fl4,
2e77d89b2   Eric Dumazet   net: avoid a pair...
286
  			    struct ipcm_cookie *ipc, struct rtable **rt)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
287
  {
1e3cf6834   Denis V. Lunev   [ICMP]: Optimize ...
288
  	struct sock *sk;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
289
  	struct sk_buff *skb;
d8d1f30b9   Changli Gao   net-next: remove ...
290
  	sk = icmp_sk(dev_net((*rt)->dst.dev));
f5fca6086   David S. Miller   ipv4: Pass flow k...
291
  	if (ip_append_data(sk, fl4, icmp_glue_bits, icmp_param,
e905a9eda   YOSHIFUJI Hideaki   [NET] IPV4: Fix w...
292
293
  			   icmp_param->data_len+icmp_param->head_len,
  			   icmp_param->head_len,
1f8438a85   Eric Dumazet   icmp: Account for...
294
295
  			   ipc, rt, MSG_DONTWAIT) < 0) {
  		ICMP_INC_STATS_BH(sock_net(sk), ICMP_MIB_OUTERRORS);
1e3cf6834   Denis V. Lunev   [ICMP]: Optimize ...
296
  		ip_flush_pending_frames(sk);
1f8438a85   Eric Dumazet   icmp: Account for...
297
  	} else if ((skb = skb_peek(&sk->sk_write_queue)) != NULL) {
88c7664f1   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
298
  		struct icmphdr *icmph = icmp_hdr(skb);
d3bc23e7e   Al Viro   [NET]: Annotate c...
299
  		__wsum csum = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
300
  		struct sk_buff *skb1;
1e3cf6834   Denis V. Lunev   [ICMP]: Optimize ...
301
  		skb_queue_walk(&sk->sk_write_queue, skb1) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
302
303
304
305
306
307
308
  			csum = csum_add(csum, skb1->csum);
  		}
  		csum = csum_partial_copy_nocheck((void *)&icmp_param->data,
  						 (char *)icmph,
  						 icmp_param->head_len, csum);
  		icmph->checksum = csum_fold(csum);
  		skb->ip_summed = CHECKSUM_NONE;
77968b782   David S. Miller   ipv4: Pass flow k...
309
  		ip_push_pending_frames(sk, fl4);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
310
311
312
313
314
315
316
317
318
  	}
  }
  
  /*
   *	Driving logic for building and sending ICMP messages.
   */
  
  static void icmp_reply(struct icmp_bxm *icmp_param, struct sk_buff *skb)
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
319
  	struct ipcm_cookie ipc;
511c3f92a   Eric Dumazet   net: skb->rtable ...
320
  	struct rtable *rt = skb_rtable(skb);
d8d1f30b9   Changli Gao   net-next: remove ...
321
  	struct net *net = dev_net(rt->dst.dev);
77968b782   David S. Miller   ipv4: Pass flow k...
322
  	struct flowi4 fl4;
fdc0bde90   Denis V. Lunev   icmp: icmp_sk() s...
323
324
  	struct sock *sk;
  	struct inet_sock *inet;
3ca3c68e7   Al Viro   [IPV4]: struct ip...
325
  	__be32 daddr;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
326

f6d8bd051   Eric Dumazet   inet: add RCU pro...
327
  	if (ip_options_echo(&icmp_param->replyopts.opt.opt, skb))
f00c401b9   Horms   [IPV4]: Remove su...
328
  		return;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
329

fdc0bde90   Denis V. Lunev   icmp: icmp_sk() s...
330
331
  	sk = icmp_xmit_lock(net);
  	if (sk == NULL)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
332
  		return;
fdc0bde90   Denis V. Lunev   icmp: icmp_sk() s...
333
  	inet = inet_sk(sk);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
334
335
  
  	icmp_param->data.icmph.checksum = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
336

eddc9ec53   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
337
  	inet->tos = ip_hdr(skb)->tos;
9f6abb5f1   David S. Miller   ipv4: icmp: Elimi...
338
  	daddr = ipc.addr = ip_hdr(skb)->saddr;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
339
  	ipc.opt = NULL;
2244d07bf   Oliver Hartkopp   net: simplify fla...
340
  	ipc.tx_flags = 0;
f6d8bd051   Eric Dumazet   inet: add RCU pro...
341
342
343
344
  	if (icmp_param->replyopts.opt.opt.optlen) {
  		ipc.opt = &icmp_param->replyopts.opt;
  		if (ipc.opt->opt.srr)
  			daddr = icmp_param->replyopts.opt.opt.faddr;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
345
  	}
77968b782   David S. Miller   ipv4: Pass flow k...
346
347
348
349
350
351
352
353
354
  	memset(&fl4, 0, sizeof(fl4));
  	fl4.daddr = daddr;
  	fl4.saddr = rt->rt_spec_dst;
  	fl4.flowi4_tos = RT_TOS(ip_hdr(skb)->tos);
  	fl4.flowi4_proto = IPPROTO_ICMP;
  	security_skb_classify_flow(skb, flowi4_to_flowi(&fl4));
  	rt = ip_route_output_key(net, &fl4);
  	if (IS_ERR(rt))
  		goto out_unlock;
a48eff128   David S. Miller   ipv4: Pass explic...
355
  	if (icmpv4_xrlim_allow(net, rt, &fl4, icmp_param->data.icmph.type,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
356
  			       icmp_param->data.icmph.code))
77968b782   David S. Miller   ipv4: Pass flow k...
357
  		icmp_push_reply(icmp_param, &fl4, &ipc, &rt);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
358
359
  	ip_rt_put(rt);
  out_unlock:
405666db8   Denis V. Lunev   [ICMP]: Pass prop...
360
  	icmp_xmit_unlock(sk);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
361
  }
77968b782   David S. Miller   ipv4: Pass flow k...
362
363
364
  static struct rtable *icmp_route_lookup(struct net *net,
  					struct flowi4 *fl4,
  					struct sk_buff *skb_in,
b71d1d426   Eric Dumazet   inet: constify ip...
365
  					const struct iphdr *iph,
f6d460cf0   David S. Miller   ipv4: Make icmp r...
366
367
368
369
  					__be32 saddr, u8 tos,
  					int type, int code,
  					struct icmp_bxm *param)
  {
f6d460cf0   David S. Miller   ipv4: Make icmp r...
370
  	struct rtable *rt, *rt2;
415b3334a   David S. Miller   icmp: Fix regress...
371
  	struct flowi4 fl4_dec;
f6d460cf0   David S. Miller   ipv4: Make icmp r...
372
  	int err;
77968b782   David S. Miller   ipv4: Pass flow k...
373
374
375
376
377
378
379
380
381
382
  	memset(fl4, 0, sizeof(*fl4));
  	fl4->daddr = (param->replyopts.opt.opt.srr ?
  		      param->replyopts.opt.opt.faddr : iph->saddr);
  	fl4->saddr = saddr;
  	fl4->flowi4_tos = RT_TOS(tos);
  	fl4->flowi4_proto = IPPROTO_ICMP;
  	fl4->fl4_icmp_type = type;
  	fl4->fl4_icmp_code = code;
  	security_skb_classify_flow(skb_in, flowi4_to_flowi(fl4));
  	rt = __ip_route_output_key(net, fl4);
b23dd4fe4   David S. Miller   ipv4: Make output...
383
384
  	if (IS_ERR(rt))
  		return rt;
f6d460cf0   David S. Miller   ipv4: Make icmp r...
385
386
387
  
  	/* No need to clone since we're just using its address. */
  	rt2 = rt;
9d6ec9380   David S. Miller   ipv4: Use flowi4 ...
388
  	rt = (struct rtable *) xfrm_lookup(net, &rt->dst,
77968b782   David S. Miller   ipv4: Pass flow k...
389
  					   flowi4_to_flowi(fl4), NULL, 0);
452edd598   David S. Miller   xfrm: Return dst ...
390
  	if (!IS_ERR(rt)) {
f6d460cf0   David S. Miller   ipv4: Make icmp r...
391
392
  		if (rt != rt2)
  			return rt;
452edd598   David S. Miller   xfrm: Return dst ...
393
  	} else if (PTR_ERR(rt) == -EPERM) {
f6d460cf0   David S. Miller   ipv4: Make icmp r...
394
  		rt = NULL;
452edd598   David S. Miller   xfrm: Return dst ...
395
396
  	} else
  		return rt;
f6d460cf0   David S. Miller   ipv4: Make icmp r...
397

415b3334a   David S. Miller   icmp: Fix regress...
398
  	err = xfrm_decode_session_reverse(skb_in, flowi4_to_flowi(&fl4_dec), AF_INET);
f6d460cf0   David S. Miller   ipv4: Make icmp r...
399
400
  	if (err)
  		goto relookup_failed;
415b3334a   David S. Miller   icmp: Fix regress...
401
402
  	if (inet_addr_type(net, fl4_dec.saddr) == RTN_LOCAL) {
  		rt2 = __ip_route_output_key(net, &fl4_dec);
b23dd4fe4   David S. Miller   ipv4: Make output...
403
404
  		if (IS_ERR(rt2))
  			err = PTR_ERR(rt2);
f6d460cf0   David S. Miller   ipv4: Make icmp r...
405
  	} else {
9d6ec9380   David S. Miller   ipv4: Use flowi4 ...
406
  		struct flowi4 fl4_2 = {};
f6d460cf0   David S. Miller   ipv4: Make icmp r...
407
  		unsigned long orefdst;
415b3334a   David S. Miller   icmp: Fix regress...
408
  		fl4_2.daddr = fl4_dec.saddr;
9d6ec9380   David S. Miller   ipv4: Use flowi4 ...
409
  		rt2 = ip_route_output_key(net, &fl4_2);
b23dd4fe4   David S. Miller   ipv4: Make output...
410
411
  		if (IS_ERR(rt2)) {
  			err = PTR_ERR(rt2);
f6d460cf0   David S. Miller   ipv4: Make icmp r...
412
  			goto relookup_failed;
b23dd4fe4   David S. Miller   ipv4: Make output...
413
  		}
f6d460cf0   David S. Miller   ipv4: Make icmp r...
414
415
  		/* Ugh! */
  		orefdst = skb_in->_skb_refdst; /* save old refdst */
415b3334a   David S. Miller   icmp: Fix regress...
416
  		err = ip_route_input(skb_in, fl4_dec.daddr, fl4_dec.saddr,
f6d460cf0   David S. Miller   ipv4: Make icmp r...
417
418
419
420
421
422
423
424
425
  				     RT_TOS(tos), rt2->dst.dev);
  
  		dst_release(&rt2->dst);
  		rt2 = skb_rtable(skb_in);
  		skb_in->_skb_refdst = orefdst; /* restore old refdst */
  	}
  
  	if (err)
  		goto relookup_failed;
9d6ec9380   David S. Miller   ipv4: Use flowi4 ...
426
  	rt2 = (struct rtable *) xfrm_lookup(net, &rt2->dst,
415b3334a   David S. Miller   icmp: Fix regress...
427
  					    flowi4_to_flowi(&fl4_dec), NULL,
9d6ec9380   David S. Miller   ipv4: Use flowi4 ...
428
  					    XFRM_LOOKUP_ICMP);
452edd598   David S. Miller   xfrm: Return dst ...
429
  	if (!IS_ERR(rt2)) {
f6d460cf0   David S. Miller   ipv4: Make icmp r...
430
  		dst_release(&rt->dst);
415b3334a   David S. Miller   icmp: Fix regress...
431
  		memcpy(fl4, &fl4_dec, sizeof(*fl4));
f6d460cf0   David S. Miller   ipv4: Make icmp r...
432
  		rt = rt2;
452edd598   David S. Miller   xfrm: Return dst ...
433
434
435
436
437
438
439
  	} else if (PTR_ERR(rt2) == -EPERM) {
  		if (rt)
  			dst_release(&rt->dst);
  		return rt2;
  	} else {
  		err = PTR_ERR(rt2);
  		goto relookup_failed;
f6d460cf0   David S. Miller   ipv4: Make icmp r...
440
  	}
f6d460cf0   David S. Miller   ipv4: Make icmp r...
441
442
443
444
445
446
447
  	return rt;
  
  relookup_failed:
  	if (rt)
  		return rt;
  	return ERR_PTR(err);
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
448
449
450
451
452
453
454
455
456
457
458
  
  /*
   *	Send an ICMP message in response to a situation
   *
   *	RFC 1122: 3.2.2	MUST send at least the IP header and 8 bytes of header.
   *		  MAY send more (we do).
   *			MUST NOT change this header information.
   *			MUST NOT reply to a multicast/broadcast IP address.
   *			MUST NOT reply to a multicast/broadcast MAC address.
   *			MUST reply to only the first fragment.
   */
e4883014f   Al Viro   [IPV4]: icmp_send...
459
  void icmp_send(struct sk_buff *skb_in, int type, int code, __be32 info)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
460
461
462
463
  {
  	struct iphdr *iph;
  	int room;
  	struct icmp_bxm icmp_param;
511c3f92a   Eric Dumazet   net: skb->rtable ...
464
  	struct rtable *rt = skb_rtable(skb_in);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
465
  	struct ipcm_cookie ipc;
77968b782   David S. Miller   ipv4: Pass flow k...
466
  	struct flowi4 fl4;
a61ced5d1   Al Viro   [IPV4]: inet_sele...
467
  	__be32 saddr;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
468
  	u8  tos;
dde1bc0e6   Denis V. Lunev   [NETNS]: Add name...
469
  	struct net *net;
4a6ad7a14   Denis V. Lunev   [NETNS]: Make icm...
470
  	struct sock *sk;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
471
472
473
  
  	if (!rt)
  		goto out;
d8d1f30b9   Changli Gao   net-next: remove ...
474
  	net = dev_net(rt->dst.dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
475
476
477
478
479
480
  
  	/*
  	 *	Find the original header. It is expected to be valid, of course.
  	 *	Check this, icmp_send is called from the most obscure devices
  	 *	sometimes.
  	 */
eddc9ec53   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
481
  	iph = ip_hdr(skb_in);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
482

27a884dc3   Arnaldo Carvalho de Melo   [SK_BUFF]: Conver...
483
484
  	if ((u8 *)iph < skb_in->head ||
  	    (skb_in->network_header + sizeof(*iph)) > skb_in->tail)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
  		goto out;
  
  	/*
  	 *	No replies to physical multicast/broadcast
  	 */
  	if (skb_in->pkt_type != PACKET_HOST)
  		goto out;
  
  	/*
  	 *	Now check at the protocol level
  	 */
  	if (rt->rt_flags & (RTCF_BROADCAST | RTCF_MULTICAST))
  		goto out;
  
  	/*
  	 *	Only reply to fragment 0. We byte re-order the constant
  	 *	mask for efficiency.
  	 */
  	if (iph->frag_off & htons(IP_OFFSET))
  		goto out;
  
  	/*
  	 *	If we send an ICMP error to an ICMP error a mess would result..
  	 */
  	if (icmp_pointers[type].error) {
  		/*
  		 *	We are an error, check if we are replying to an
  		 *	ICMP error
  		 */
  		if (iph->protocol == IPPROTO_ICMP) {
  			u8 _inner_type, *itp;
  
  			itp = skb_header_pointer(skb_in,
d56f90a7c   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
518
  						 skb_network_header(skb_in) +
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
  						 (iph->ihl << 2) +
  						 offsetof(struct icmphdr,
  							  type) -
  						 skb_in->data,
  						 sizeof(_inner_type),
  						 &_inner_type);
  			if (itp == NULL)
  				goto out;
  
  			/*
  			 *	Assume any unknown ICMP type is an error. This
  			 *	isn't specified by the RFC, but think about it..
  			 */
  			if (*itp > NR_ICMP_TYPES ||
  			    icmp_pointers[*itp].error)
  				goto out;
  		}
  	}
fdc0bde90   Denis V. Lunev   icmp: icmp_sk() s...
537
538
  	sk = icmp_xmit_lock(net);
  	if (sk == NULL)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
539
540
541
542
543
544
545
  		return;
  
  	/*
  	 *	Construct source address and options.
  	 */
  
  	saddr = iph->daddr;
1c2fb7f93   J. Simonetti   [IPV4]: Sysctl co...
546
  	if (!(rt->rt_flags & RTCF_LOCAL)) {
6e1d91039   Patrick McHardy   [ICMP]: Fix icmp_...
547
  		struct net_device *dev = NULL;
685c79440   Eric Dumazet   icmp: icmp_send()...
548
  		rcu_read_lock();
c75379676   David S. Miller   ipv4: Make rt->fl...
549
550
  		if (rt_is_input_route(rt) &&
  		    net->ipv4.sysctl_icmp_errors_use_inbound_ifaddr)
5e2b61f78   David S. Miller   ipv4: Remove flow...
551
  			dev = dev_get_by_index_rcu(net, rt->rt_iif);
6e1d91039   Patrick McHardy   [ICMP]: Fix icmp_...
552

685c79440   Eric Dumazet   icmp: icmp_send()...
553
  		if (dev)
6e1d91039   Patrick McHardy   [ICMP]: Fix icmp_...
554
  			saddr = inet_select_addr(dev, 0, RT_SCOPE_LINK);
685c79440   Eric Dumazet   icmp: icmp_send()...
555
  		else
1c2fb7f93   J. Simonetti   [IPV4]: Sysctl co...
556
  			saddr = 0;
685c79440   Eric Dumazet   icmp: icmp_send()...
557
  		rcu_read_unlock();
1c2fb7f93   J. Simonetti   [IPV4]: Sysctl co...
558
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
559
560
561
562
  
  	tos = icmp_pointers[type].error ? ((iph->tos & IPTOS_TOS_MASK) |
  					   IPTOS_PREC_INTERNETCONTROL) :
  					  iph->tos;
f6d8bd051   Eric Dumazet   inet: add RCU pro...
563
  	if (ip_options_echo(&icmp_param.replyopts.opt.opt, skb_in))
fa60cf7f6   Herbert Xu   [ICMP]: Fix extra...
564
  		goto out_unlock;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
565
566
567
568
569
570
571
572
573
574
575
  
  
  	/*
  	 *	Prepare data for ICMP header.
  	 */
  
  	icmp_param.data.icmph.type	 = type;
  	icmp_param.data.icmph.code	 = code;
  	icmp_param.data.icmph.un.gateway = info;
  	icmp_param.data.icmph.checksum	 = 0;
  	icmp_param.skb	  = skb_in;
d56f90a7c   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
576
  	icmp_param.offset = skb_network_offset(skb_in);
405666db8   Denis V. Lunev   [ICMP]: Pass prop...
577
  	inet_sk(sk)->tos = tos;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
578
  	ipc.addr = iph->saddr;
f6d8bd051   Eric Dumazet   inet: add RCU pro...
579
  	ipc.opt = &icmp_param.replyopts.opt;
2244d07bf   Oliver Hartkopp   net: simplify fla...
580
  	ipc.tx_flags = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
581

77968b782   David S. Miller   ipv4: Pass flow k...
582
  	rt = icmp_route_lookup(net, &fl4, skb_in, iph, saddr, tos,
f6d460cf0   David S. Miller   ipv4: Make icmp r...
583
584
585
  			       type, code, &icmp_param);
  	if (IS_ERR(rt))
  		goto out_unlock;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
586

a48eff128   David S. Miller   ipv4: Pass explic...
587
  	if (!icmpv4_xrlim_allow(net, rt, &fl4, type, code))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
588
589
590
  		goto ende;
  
  	/* RFC says return as much as we can without exceeding 576 bytes. */
d8d1f30b9   Changli Gao   net-next: remove ...
591
  	room = dst_mtu(&rt->dst);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
592
593
  	if (room > 576)
  		room = 576;
f6d8bd051   Eric Dumazet   inet: add RCU pro...
594
  	room -= sizeof(struct iphdr) + icmp_param.replyopts.opt.opt.optlen;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
595
596
597
598
599
600
  	room -= sizeof(struct icmphdr);
  
  	icmp_param.data_len = skb_in->len - icmp_param.offset;
  	if (icmp_param.data_len > room)
  		icmp_param.data_len = room;
  	icmp_param.head_len = sizeof(struct icmphdr);
77968b782   David S. Miller   ipv4: Pass flow k...
601
  	icmp_push_reply(&icmp_param, &fl4, &ipc, &rt);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
602
603
604
  ende:
  	ip_rt_put(rt);
  out_unlock:
405666db8   Denis V. Lunev   [ICMP]: Pass prop...
605
  	icmp_xmit_unlock(sk);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
606
607
  out:;
  }
4bc2f18ba   Eric Dumazet   net/ipv4: EXPORT_...
608
  EXPORT_SYMBOL(icmp_send);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
609
610
611
612
613
614
615
616
  
  
  /*
   *	Handle ICMP_DEST_UNREACH, ICMP_TIME_EXCEED, and ICMP_QUENCH.
   */
  
  static void icmp_unreach(struct sk_buff *skb)
  {
b71d1d426   Eric Dumazet   inet: constify ip...
617
  	const struct iphdr *iph;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
618
619
  	struct icmphdr *icmph;
  	int hash, protocol;
32613090a   Alexey Dobriyan   net: constify str...
620
  	const struct net_protocol *ipprot;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
621
  	u32 info = 0;
dde1bc0e6   Denis V. Lunev   [NETNS]: Add name...
622
  	struct net *net;
adf30907d   Eric Dumazet   net: skb->dst acc...
623
  	net = dev_net(skb_dst(skb)->dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
624
625
626
627
628
629
630
631
632
  
  	/*
  	 *	Incomplete header ?
  	 * 	Only checks for the IP header, there should be an
  	 *	additional check for longer headers in upper levels.
  	 */
  
  	if (!pskb_may_pull(skb, sizeof(struct iphdr)))
  		goto out_err;
88c7664f1   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
633
  	icmph = icmp_hdr(skb);
b71d1d426   Eric Dumazet   inet: constify ip...
634
  	iph   = (const struct iphdr *)skb->data;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
635
636
637
638
639
640
641
642
643
644
645
646
647
  
  	if (iph->ihl < 5) /* Mangled header, drop. */
  		goto out_err;
  
  	if (icmph->type == ICMP_DEST_UNREACH) {
  		switch (icmph->code & 15) {
  		case ICMP_NET_UNREACH:
  		case ICMP_HOST_UNREACH:
  		case ICMP_PROT_UNREACH:
  		case ICMP_PORT_UNREACH:
  			break;
  		case ICMP_FRAG_NEEDED:
  			if (ipv4_config.no_pmtu_disc) {
673d57e72   Harvey Harrison   net: replace NIPQ...
648
649
650
  				LIMIT_NETDEBUG(KERN_INFO "ICMP: %pI4: fragmentation needed and DF set.
  ",
  					       &iph->daddr);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
651
  			} else {
dde1bc0e6   Denis V. Lunev   [NETNS]: Add name...
652
  				info = ip_rt_frag_needed(net, iph,
0010e4657   Timo Teras   ipv4: Update MTU ...
653
654
  							 ntohs(icmph->un.frag.mtu),
  							 skb->dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
655
656
657
658
659
  				if (!info)
  					goto out;
  			}
  			break;
  		case ICMP_SR_FAILED:
673d57e72   Harvey Harrison   net: replace NIPQ...
660
661
662
  			LIMIT_NETDEBUG(KERN_INFO "ICMP: %pI4: Source Route Failed.
  ",
  				       &iph->daddr);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
  			break;
  		default:
  			break;
  		}
  		if (icmph->code > NR_ICMP_UNREACH)
  			goto out;
  	} else if (icmph->type == ICMP_PARAMETERPROB)
  		info = ntohl(icmph->un.gateway) >> 24;
  
  	/*
  	 *	Throw it at our lower layers
  	 *
  	 *	RFC 1122: 3.2.2 MUST extract the protocol ID from the passed
  	 *		  header.
  	 *	RFC 1122: 3.2.2.1 MUST pass ICMP unreach messages to the
  	 *		  transport layer.
  	 *	RFC 1122: 3.2.2.2 MUST pass ICMP time expired messages to
  	 *		  transport layer.
  	 */
  
  	/*
25985edce   Lucas De Marchi   Fix common misspe...
684
  	 *	Check the other end isn't violating RFC 1122. Some routers send
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
685
686
687
688
  	 *	bogus responses to broadcast frames. If you see this message
  	 *	first check your netmask matches at both ends, if it does then
  	 *	get the other vendor to fix their kit.
  	 */
b34a95ee6   Pavel Emelyanov   [NETNS][ICMP]: Us...
689
  	if (!net->ipv4.sysctl_icmp_ignore_bogus_error_responses &&
dde1bc0e6   Denis V. Lunev   [NETNS]: Add name...
690
  	    inet_addr_type(net, iph->daddr) == RTN_BROADCAST) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
691
  		if (net_ratelimit())
673d57e72   Harvey Harrison   net: replace NIPQ...
692
  			printk(KERN_WARNING "%pI4 sent an invalid ICMP "
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
693
  					    "type %u, code %u "
673d57e72   Harvey Harrison   net: replace NIPQ...
694
695
696
  					    "error to a broadcast: %pI4 on %s
  ",
  			       &ip_hdr(skb)->saddr,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
697
  			       icmph->type, icmph->code,
673d57e72   Harvey Harrison   net: replace NIPQ...
698
  			       &iph->daddr,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
699
700
701
702
703
704
705
706
707
  			       skb->dev->name);
  		goto out;
  	}
  
  	/* Checkin full IP header plus 8 bytes of protocol to
  	 * avoid additional coding at protocol handlers.
  	 */
  	if (!pskb_may_pull(skb, iph->ihl * 4 + 8))
  		goto out;
b71d1d426   Eric Dumazet   inet: constify ip...
708
  	iph = (const struct iphdr *)skb->data;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
709
710
711
712
713
  	protocol = iph->protocol;
  
  	/*
  	 *	Deliver ICMP message to raw sockets. Pretty useless feature?
  	 */
7bc54c903   Pavel Emelyanov   [IPv4] RAW: Compa...
714
  	raw_icmp_error(skb, protocol, info);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
715

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
716
  	hash = protocol & (MAX_INET_PROTOS - 1);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
717
718
719
720
721
722
723
724
725
  	rcu_read_lock();
  	ipprot = rcu_dereference(inet_protos[hash]);
  	if (ipprot && ipprot->err_handler)
  		ipprot->err_handler(skb, info);
  	rcu_read_unlock();
  
  out:
  	return;
  out_err:
dcfc23cac   Pavel Emelyanov   mib: add struct n...
726
  	ICMP_INC_STATS_BH(net, ICMP_MIB_INERRORS);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
727
728
729
730
731
732
733
734
735
736
  	goto out;
  }
  
  
  /*
   *	Handle ICMP_REDIRECT.
   */
  
  static void icmp_redirect(struct sk_buff *skb)
  {
b71d1d426   Eric Dumazet   inet: constify ip...
737
  	const struct iphdr *iph;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
738
739
740
741
742
743
744
745
746
  
  	if (skb->len < sizeof(struct iphdr))
  		goto out_err;
  
  	/*
  	 *	Get the copied header of the packet that caused the redirect
  	 */
  	if (!pskb_may_pull(skb, sizeof(struct iphdr)))
  		goto out;
b71d1d426   Eric Dumazet   inet: constify ip...
747
  	iph = (const struct iphdr *)skb->data;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
748

88c7664f1   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
749
  	switch (icmp_hdr(skb)->code & 7) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
750
751
752
753
754
755
756
  	case ICMP_REDIR_NET:
  	case ICMP_REDIR_NETTOS:
  		/*
  		 * As per RFC recommendations now handle it as a host redirect.
  		 */
  	case ICMP_REDIR_HOST:
  	case ICMP_REDIR_HOSTTOS:
eddc9ec53   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
757
  		ip_rt_redirect(ip_hdr(skb)->saddr, iph->daddr,
88c7664f1   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
758
  			       icmp_hdr(skb)->un.gateway,
cef2685e0   Ilia Sotnikov   [IPV4]: Aggregate...
759
  			       iph->saddr, skb->dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
760
  		break;
e905a9eda   YOSHIFUJI Hideaki   [NET] IPV4: Fix w...
761
  	}
c319b4d76   Vasiliy Kulikov   net: ipv4: add IP...
762
763
764
765
766
767
768
769
  
  	/* Ping wants to see redirects.
           * Let's pretend they are errors of sorts... */
  	if (iph->protocol == IPPROTO_ICMP &&
  	    iph->ihl >= 5 &&
  	    pskb_may_pull(skb, (iph->ihl<<2)+8)) {
  		ping_err(skb, icmp_hdr(skb)->un.gateway);
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
770
771
772
  out:
  	return;
  out_err:
dcfc23cac   Pavel Emelyanov   mib: add struct n...
773
  	ICMP_INC_STATS_BH(dev_net(skb->dev), ICMP_MIB_INERRORS);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
  	goto out;
  }
  
  /*
   *	Handle ICMP_ECHO ("ping") requests.
   *
   *	RFC 1122: 3.2.2.6 MUST have an echo server that answers ICMP echo
   *		  requests.
   *	RFC 1122: 3.2.2.6 Data received in the ICMP_ECHO request MUST be
   *		  included in the reply.
   *	RFC 1812: 4.3.3.6 SHOULD have a config option for silently ignoring
   *		  echo requests, MUST have default=NOT.
   *	See also WRT handling of options once they are done and working.
   */
  
  static void icmp_echo(struct sk_buff *skb)
  {
b34a95ee6   Pavel Emelyanov   [NETNS][ICMP]: Us...
791
  	struct net *net;
adf30907d   Eric Dumazet   net: skb->dst acc...
792
  	net = dev_net(skb_dst(skb)->dev);
b34a95ee6   Pavel Emelyanov   [NETNS][ICMP]: Us...
793
  	if (!net->ipv4.sysctl_icmp_echo_ignore_all) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
794
  		struct icmp_bxm icmp_param;
88c7664f1   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
795
  		icmp_param.data.icmph	   = *icmp_hdr(skb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
  		icmp_param.data.icmph.type = ICMP_ECHOREPLY;
  		icmp_param.skb		   = skb;
  		icmp_param.offset	   = 0;
  		icmp_param.data_len	   = skb->len;
  		icmp_param.head_len	   = sizeof(struct icmphdr);
  		icmp_reply(&icmp_param, skb);
  	}
  }
  
  /*
   *	Handle ICMP Timestamp requests.
   *	RFC 1122: 3.2.2.8 MAY implement ICMP timestamp requests.
   *		  SHOULD be in the kernel for minimum random latency.
   *		  MUST be accurate to a few minutes.
   *		  MUST be updated at least at 15Hz.
   */
  static void icmp_timestamp(struct sk_buff *skb)
  {
f25c3d613   YOSHIFUJI Hideaki   [IPV4]: Convert d...
814
  	struct timespec tv;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
815
816
817
818
819
820
821
822
823
824
  	struct icmp_bxm icmp_param;
  	/*
  	 *	Too short.
  	 */
  	if (skb->len < 4)
  		goto out_err;
  
  	/*
  	 *	Fill in the current time as ms since midnight UT:
  	 */
f25c3d613   YOSHIFUJI Hideaki   [IPV4]: Convert d...
825
826
827
  	getnstimeofday(&tv);
  	icmp_param.data.times[1] = htonl((tv.tv_sec % 86400) * MSEC_PER_SEC +
  					 tv.tv_nsec / NSEC_PER_MSEC);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
828
829
830
  	icmp_param.data.times[2] = icmp_param.data.times[1];
  	if (skb_copy_bits(skb, 0, &icmp_param.data.times[0], 4))
  		BUG();
88c7664f1   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
831
  	icmp_param.data.icmph	   = *icmp_hdr(skb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
832
833
834
835
836
837
838
839
840
841
  	icmp_param.data.icmph.type = ICMP_TIMESTAMPREPLY;
  	icmp_param.data.icmph.code = 0;
  	icmp_param.skb		   = skb;
  	icmp_param.offset	   = 0;
  	icmp_param.data_len	   = 0;
  	icmp_param.head_len	   = sizeof(struct icmphdr) + 12;
  	icmp_reply(&icmp_param, skb);
  out:
  	return;
  out_err:
adf30907d   Eric Dumazet   net: skb->dst acc...
842
  	ICMP_INC_STATS_BH(dev_net(skb_dst(skb)->dev), ICMP_MIB_INERRORS);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
  	goto out;
  }
  
  
  /*
   *	Handle ICMP_ADDRESS_MASK requests.  (RFC950)
   *
   * RFC1122 (3.2.2.9).  A host MUST only send replies to
   * ADDRESS_MASK requests if it's been configured as an address mask
   * agent.  Receiving a request doesn't constitute implicit permission to
   * act as one. Of course, implementing this correctly requires (SHOULD)
   * a way to turn the functionality on and off.  Another one for sysctl(),
   * I guess. -- MS
   *
   * RFC1812 (4.3.3.9).	A router MUST implement it.
   *			A router SHOULD have switch turning it on/off.
   *		      	This switch MUST be ON by default.
   *
   * Gratuitous replies, zero-source replies are not implemented,
   * that complies with RFC. DO NOT implement them!!! All the idea
   * of broadcast addrmask replies as specified in RFC950 is broken.
   * The problem is that it is not uncommon to have several prefixes
   * on one physical interface. Moreover, addrmask agent can even be
   * not aware of existing another prefixes.
   * If source is zero, addrmask agent cannot choose correct prefix.
   * Gratuitous mask announcements suffer from the same problem.
   * RFC1812 explains it, but still allows to use ADDRMASK,
   * that is pretty silly. --ANK
   *
   * All these rules are so bizarre, that I removed kernel addrmask
   * support at all. It is wrong, it is obsolete, nobody uses it in
   * any case. --ANK
   *
   * Furthermore you can do it with a usermode address agent program
   * anyway...
   */
  
  static void icmp_address(struct sk_buff *skb)
  {
  #if 0
  	if (net_ratelimit())
  		printk(KERN_DEBUG "a guy asks for address mask. Who is it?
  ");
  #endif
  }
  
  /*
   * RFC1812 (4.3.3.9).	A router SHOULD listen all replies, and complain
   *			loudly if an inconsistency is found.
cfa087f68   Eric Dumazet   icmp: RCU convers...
892
   * called with rcu_read_lock()
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
893
894
895
896
   */
  
  static void icmp_address_reply(struct sk_buff *skb)
  {
511c3f92a   Eric Dumazet   net: skb->rtable ...
897
  	struct rtable *rt = skb_rtable(skb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
898
899
900
901
902
  	struct net_device *dev = skb->dev;
  	struct in_device *in_dev;
  	struct in_ifaddr *ifa;
  
  	if (skb->len < 4 || !(rt->rt_flags&RTCF_DIRECTSRC))
cfa087f68   Eric Dumazet   icmp: RCU convers...
903
  		return;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
904

cfa087f68   Eric Dumazet   icmp: RCU convers...
905
  	in_dev = __in_dev_get_rcu(dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
906
  	if (!in_dev)
cfa087f68   Eric Dumazet   icmp: RCU convers...
907
  		return;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
908
909
910
  	if (in_dev->ifa_list &&
  	    IN_DEV_LOG_MARTIANS(in_dev) &&
  	    IN_DEV_FORWARD(in_dev)) {
a144ea4b7   Al Viro   [IPV4]: annotate ...
911
  		__be32 _mask, *mp;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
912
913
  
  		mp = skb_header_pointer(skb, 0, sizeof(_mask), &_mask);
09a626600   Kris Katterjohn   [NET]: Change som...
914
  		BUG_ON(mp == NULL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
915
916
  		for (ifa = in_dev->ifa_list; ifa; ifa = ifa->ifa_next) {
  			if (*mp == ifa->ifa_mask &&
9f6abb5f1   David S. Miller   ipv4: icmp: Elimi...
917
  			    inet_ifa_match(ip_hdr(skb)->saddr, ifa))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
918
919
920
  				break;
  		}
  		if (!ifa && net_ratelimit()) {
673d57e72   Harvey Harrison   net: replace NIPQ...
921
922
  			printk(KERN_INFO "Wrong address mask %pI4 from %s/%pI4
  ",
9f6abb5f1   David S. Miller   ipv4: icmp: Elimi...
923
  			       mp, dev->name, &ip_hdr(skb)->saddr);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
924
925
  		}
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
926
927
928
929
930
931
932
933
934
935
936
937
  }
  
  static void icmp_discard(struct sk_buff *skb)
  {
  }
  
  /*
   *	Deal with incoming ICMP packets.
   */
  int icmp_rcv(struct sk_buff *skb)
  {
  	struct icmphdr *icmph;
511c3f92a   Eric Dumazet   net: skb->rtable ...
938
  	struct rtable *rt = skb_rtable(skb);
d8d1f30b9   Changli Gao   net-next: remove ...
939
  	struct net *net = dev_net(rt->dst.dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
940

aebcf82c1   Herbert Xu   [IPSEC]: Do not l...
941
  	if (!xfrm4_policy_check(NULL, XFRM_POLICY_IN, skb)) {
def8b4faf   Alexey Dobriyan   net: reduce struc...
942
  		struct sec_path *sp = skb_sec_path(skb);
8b7817f3a   Herbert Xu   [IPSEC]: Add ICMP...
943
  		int nh;
def8b4faf   Alexey Dobriyan   net: reduce struc...
944
  		if (!(sp && sp->xvec[sp->len - 1]->props.flags &
aebcf82c1   Herbert Xu   [IPSEC]: Do not l...
945
946
  				 XFRM_STATE_ICMP))
  			goto drop;
8b7817f3a   Herbert Xu   [IPSEC]: Add ICMP...
947
948
949
950
951
952
953
954
955
956
957
  		if (!pskb_may_pull(skb, sizeof(*icmph) + sizeof(struct iphdr)))
  			goto drop;
  
  		nh = skb_network_offset(skb);
  		skb_set_network_header(skb, sizeof(*icmph));
  
  		if (!xfrm4_policy_check_reverse(NULL, XFRM_POLICY_IN, skb))
  			goto drop;
  
  		skb_set_network_header(skb, nh);
  	}
dcfc23cac   Pavel Emelyanov   mib: add struct n...
958
  	ICMP_INC_STATS_BH(net, ICMP_MIB_INMSGS);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
959
960
  
  	switch (skb->ip_summed) {
84fa7933a   Patrick McHardy   [NET]: Replace CH...
961
  	case CHECKSUM_COMPLETE:
d3bc23e7e   Al Viro   [NET]: Annotate c...
962
  		if (!csum_fold(skb->csum))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
963
  			break;
fb286bb29   Herbert Xu   [NET]: Detect har...
964
  		/* fall through */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
965
  	case CHECKSUM_NONE:
fb286bb29   Herbert Xu   [NET]: Detect har...
966
967
  		skb->csum = 0;
  		if (__skb_checksum_complete(skb))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
968
  			goto error;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
969
  	}
8cf229437   Herbert Xu   [ICMP]: Restore p...
970
971
  	if (!pskb_pull(skb, sizeof(*icmph)))
  		goto error;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
972

88c7664f1   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
973
  	icmph = icmp_hdr(skb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
974

f66ac03d4   Pavel Emelyanov   mib: add struct n...
975
  	ICMPMSGIN_INC_STATS_BH(net, icmph->type);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
976
977
978
979
980
981
982
983
984
985
986
987
988
  	/*
  	 *	18 is the highest 'known' ICMP type. Anything else is a mystery
  	 *
  	 *	RFC 1122: 3.2.2  Unknown ICMP messages types MUST be silently
  	 *		  discarded.
  	 */
  	if (icmph->type > NR_ICMP_TYPES)
  		goto error;
  
  
  	/*
  	 *	Parse the ICMP message
  	 */
e905a9eda   YOSHIFUJI Hideaki   [NET] IPV4: Fix w...
989
  	if (rt->rt_flags & (RTCF_BROADCAST | RTCF_MULTICAST)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
990
991
992
993
994
995
  		/*
  		 *	RFC 1122: 3.2.2.6 An ICMP_ECHO to broadcast MAY be
  		 *	  silently ignored (we let user decide with a sysctl).
  		 *	RFC 1122: 3.2.2.8 An ICMP_TIMESTAMP MAY be silently
  		 *	  discarded if to broadcast/multicast.
  		 */
4c866aa79   Alexey Kuznetsov   [IPV4]: Apply sys...
996
997
  		if ((icmph->type == ICMP_ECHO ||
  		     icmph->type == ICMP_TIMESTAMP) &&
b34a95ee6   Pavel Emelyanov   [NETNS][ICMP]: Us...
998
  		    net->ipv4.sysctl_icmp_echo_ignore_broadcasts) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
999
1000
1001
1002
1003
1004
1005
  			goto error;
  		}
  		if (icmph->type != ICMP_ECHO &&
  		    icmph->type != ICMP_TIMESTAMP &&
  		    icmph->type != ICMP_ADDRESS &&
  		    icmph->type != ICMP_ADDRESSREPLY) {
  			goto error;
e905a9eda   YOSHIFUJI Hideaki   [NET] IPV4: Fix w...
1006
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1007
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1008
1009
1010
1011
1012
1013
  	icmp_pointers[icmph->type].handler(skb);
  
  drop:
  	kfree_skb(skb);
  	return 0;
  error:
dcfc23cac   Pavel Emelyanov   mib: add struct n...
1014
  	ICMP_INC_STATS_BH(net, ICMP_MIB_INERRORS);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1015
1016
1017
1018
1019
1020
  	goto drop;
  }
  
  /*
   *	This table is the definition of how we handle ICMP.
   */
9b5b5cff9   Arjan van de Ven   [NET]: Add const ...
1021
  static const struct icmp_control icmp_pointers[NR_ICMP_TYPES + 1] = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1022
  	[ICMP_ECHOREPLY] = {
c319b4d76   Vasiliy Kulikov   net: ipv4: add IP...
1023
  		.handler = ping_rcv,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1024
1025
  	},
  	[1] = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1026
1027
1028
1029
  		.handler = icmp_discard,
  		.error = 1,
  	},
  	[2] = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1030
1031
1032
1033
  		.handler = icmp_discard,
  		.error = 1,
  	},
  	[ICMP_DEST_UNREACH] = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1034
1035
1036
1037
  		.handler = icmp_unreach,
  		.error = 1,
  	},
  	[ICMP_SOURCE_QUENCH] = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1038
1039
1040
1041
  		.handler = icmp_unreach,
  		.error = 1,
  	},
  	[ICMP_REDIRECT] = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1042
1043
1044
1045
  		.handler = icmp_redirect,
  		.error = 1,
  	},
  	[6] = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1046
1047
1048
1049
  		.handler = icmp_discard,
  		.error = 1,
  	},
  	[7] = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1050
1051
1052
1053
  		.handler = icmp_discard,
  		.error = 1,
  	},
  	[ICMP_ECHO] = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1054
1055
1056
  		.handler = icmp_echo,
  	},
  	[9] = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1057
1058
1059
1060
  		.handler = icmp_discard,
  		.error = 1,
  	},
  	[10] = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1061
1062
1063
1064
  		.handler = icmp_discard,
  		.error = 1,
  	},
  	[ICMP_TIME_EXCEEDED] = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1065
1066
1067
1068
  		.handler = icmp_unreach,
  		.error = 1,
  	},
  	[ICMP_PARAMETERPROB] = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1069
1070
1071
1072
  		.handler = icmp_unreach,
  		.error = 1,
  	},
  	[ICMP_TIMESTAMP] = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1073
1074
1075
  		.handler = icmp_timestamp,
  	},
  	[ICMP_TIMESTAMPREPLY] = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1076
1077
1078
  		.handler = icmp_discard,
  	},
  	[ICMP_INFO_REQUEST] = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1079
1080
  		.handler = icmp_discard,
  	},
e905a9eda   YOSHIFUJI Hideaki   [NET] IPV4: Fix w...
1081
  	[ICMP_INFO_REPLY] = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1082
1083
1084
  		.handler = icmp_discard,
  	},
  	[ICMP_ADDRESS] = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1085
1086
1087
  		.handler = icmp_address,
  	},
  	[ICMP_ADDRESSREPLY] = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1088
1089
1090
  		.handler = icmp_address_reply,
  	},
  };
4a6ad7a14   Denis V. Lunev   [NETNS]: Make icm...
1091
  static void __net_exit icmp_sk_exit(struct net *net)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1092
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1093
  	int i;
5c8cafd65   Denis V. Lunev   [NETNS]: icmp(v6)...
1094
  	for_each_possible_cpu(i)
c1e9894d4   Denis V. Lunev   [ICMP]: Simplify ...
1095
  		inet_ctl_sock_destroy(net->ipv4.icmp_sk[i]);
4a6ad7a14   Denis V. Lunev   [NETNS]: Make icm...
1096
1097
  	kfree(net->ipv4.icmp_sk);
  	net->ipv4.icmp_sk = NULL;
a5710d658   Denis V. Lunev   [ICMP]: Add retur...
1098
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1099

263173af5   Adrian Bunk   [IPV4]: Make icmp...
1100
  static int __net_init icmp_sk_init(struct net *net)
a5710d658   Denis V. Lunev   [ICMP]: Add retur...
1101
  {
a5710d658   Denis V. Lunev   [ICMP]: Add retur...
1102
  	int i, err;
4a6ad7a14   Denis V. Lunev   [NETNS]: Make icm...
1103
1104
1105
  	net->ipv4.icmp_sk =
  		kzalloc(nr_cpu_ids * sizeof(struct sock *), GFP_KERNEL);
  	if (net->ipv4.icmp_sk == NULL)
79c911595   Denis V. Lunev   [ICMP]: Allocate ...
1106
  		return -ENOMEM;
a5710d658   Denis V. Lunev   [ICMP]: Add retur...
1107
  	for_each_possible_cpu(i) {
1e3cf6834   Denis V. Lunev   [ICMP]: Optimize ...
1108
  		struct sock *sk;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1109

c1e9894d4   Denis V. Lunev   [ICMP]: Simplify ...
1110
1111
  		err = inet_ctl_sock_create(&sk, PF_INET,
  					   SOCK_RAW, IPPROTO_ICMP, net);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1112
  		if (err < 0)
a5710d658   Denis V. Lunev   [ICMP]: Add retur...
1113
  			goto fail;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1114

c1e9894d4   Denis V. Lunev   [ICMP]: Simplify ...
1115
  		net->ipv4.icmp_sk[i] = sk;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1116
1117
  
  		/* Enough space for 2 64K ICMP packets, including
87fb4b7b5   Eric Dumazet   net: more accurat...
1118
  		 * sk_buff/skb_shared_info struct overhead.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1119
  		 */
87fb4b7b5   Eric Dumazet   net: more accurat...
1120
  		sk->sk_sndbuf =	2 * SKB_TRUESIZE(64 * 1024);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1121

b3a5b6cc7   Eric Dumazet   icmp: No need to ...
1122
1123
1124
1125
  		/*
  		 * Speedup sock_wfree()
  		 */
  		sock_set_flag(sk, SOCK_USE_WRITE_QUEUE);
c1e9894d4   Denis V. Lunev   [ICMP]: Simplify ...
1126
  		inet_sk(sk)->pmtudisc = IP_PMTUDISC_DONT;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1127
  	}
a24022e18   Pavel Emelyanov   [NETNS][ICMP]: Mo...
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
  
  	/* Control parameters for ECHO replies. */
  	net->ipv4.sysctl_icmp_echo_ignore_all = 0;
  	net->ipv4.sysctl_icmp_echo_ignore_broadcasts = 1;
  
  	/* Control parameter - ignore bogus broadcast responses? */
  	net->ipv4.sysctl_icmp_ignore_bogus_error_responses = 1;
  
  	/*
  	 * 	Configurable global rate limit.
  	 *
  	 *	ratelimit defines tokens/packet consumed for dst->rate_token
  	 *	bucket ratemask defines which icmp types are ratelimited by
  	 *	setting	it's bit position.
  	 *
  	 *	default:
  	 *	dest unreachable (3), source quench (4),
  	 *	time exceeded (11), parameter problem (12)
  	 */
  
  	net->ipv4.sysctl_icmp_ratelimit = 1 * HZ;
  	net->ipv4.sysctl_icmp_ratemask = 0x1818;
  	net->ipv4.sysctl_icmp_errors_use_inbound_ifaddr = 0;
a5710d658   Denis V. Lunev   [ICMP]: Add retur...
1151
1152
1153
  	return 0;
  
  fail:
1d1c8d13c   Denis V. Lunev   [ICMP]: Section c...
1154
  	for_each_possible_cpu(i)
c1e9894d4   Denis V. Lunev   [ICMP]: Simplify ...
1155
  		inet_ctl_sock_destroy(net->ipv4.icmp_sk[i]);
1d1c8d13c   Denis V. Lunev   [ICMP]: Section c...
1156
  	kfree(net->ipv4.icmp_sk);
a5710d658   Denis V. Lunev   [ICMP]: Add retur...
1157
  	return err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1158
  }
4a6ad7a14   Denis V. Lunev   [NETNS]: Make icm...
1159
1160
1161
1162
1163
1164
1165
  static struct pernet_operations __net_initdata icmp_sk_ops = {
         .init = icmp_sk_init,
         .exit = icmp_sk_exit,
  };
  
  int __init icmp_init(void)
  {
959d27264   Eric W. Biederman   netns: Fix icmp s...
1166
  	return register_pernet_subsys(&icmp_sk_ops);
4a6ad7a14   Denis V. Lunev   [NETNS]: Make icm...
1167
  }