xref: /openbmc/linux/net/ipv4/icmp.c (revision 5f92a7388a29594d6c365b23a48d4bb8299a3ea7)
11da177e4SLinus Torvalds /*
21da177e4SLinus Torvalds  *	NET3:	Implementation of the ICMP protocol layer.
31da177e4SLinus Torvalds  *
41da177e4SLinus Torvalds  *		Alan Cox, <alan@redhat.com>
51da177e4SLinus Torvalds  *
61da177e4SLinus Torvalds  *	Version: $Id: icmp.c,v 1.85 2002/02/01 22:01:03 davem Exp $
71da177e4SLinus Torvalds  *
81da177e4SLinus Torvalds  *	This program is free software; you can redistribute it and/or
91da177e4SLinus Torvalds  *	modify it under the terms of the GNU General Public License
101da177e4SLinus Torvalds  *	as published by the Free Software Foundation; either version
111da177e4SLinus Torvalds  *	2 of the License, or (at your option) any later version.
121da177e4SLinus Torvalds  *
131da177e4SLinus Torvalds  *	Some of the function names and the icmp unreach table for this
141da177e4SLinus Torvalds  *	module were derived from [icmp.c 1.0.11 06/02/93] by
151da177e4SLinus Torvalds  *	Ross Biro, Fred N. van Kempen, Mark Evans, Alan Cox, Gerhard Koerting.
161da177e4SLinus Torvalds  *	Other than that this module is a complete rewrite.
171da177e4SLinus Torvalds  *
181da177e4SLinus Torvalds  *	Fixes:
191da177e4SLinus Torvalds  *	Clemens Fruhwirth	:	introduce global icmp rate limiting
201da177e4SLinus Torvalds  *					with icmp type masking ability instead
211da177e4SLinus Torvalds  *					of broken per type icmp timeouts.
221da177e4SLinus Torvalds  *		Mike Shaver	:	RFC1122 checks.
231da177e4SLinus Torvalds  *		Alan Cox	:	Multicast ping reply as self.
241da177e4SLinus Torvalds  *		Alan Cox	:	Fix atomicity lockup in ip_build_xmit
251da177e4SLinus Torvalds  *					call.
261da177e4SLinus Torvalds  *		Alan Cox	:	Added 216,128 byte paths to the MTU
271da177e4SLinus Torvalds  *					code.
281da177e4SLinus Torvalds  *		Martin Mares	:	RFC1812 checks.
291da177e4SLinus Torvalds  *		Martin Mares	:	Can be configured to follow redirects
301da177e4SLinus Torvalds  *					if acting as a router _without_ a
311da177e4SLinus Torvalds  *					routing protocol (RFC 1812).
321da177e4SLinus Torvalds  *		Martin Mares	:	Echo requests may be configured to
331da177e4SLinus Torvalds  *					be ignored (RFC 1812).
341da177e4SLinus Torvalds  *		Martin Mares	:	Limitation of ICMP error message
351da177e4SLinus Torvalds  *					transmit rate (RFC 1812).
361da177e4SLinus Torvalds  *		Martin Mares	:	TOS and Precedence set correctly
371da177e4SLinus Torvalds  *					(RFC 1812).
381da177e4SLinus Torvalds  *		Martin Mares	:	Now copying as much data from the
391da177e4SLinus Torvalds  *					original packet as we can without
401da177e4SLinus Torvalds  *					exceeding 576 bytes (RFC 1812).
411da177e4SLinus Torvalds  *	Willy Konynenberg	:	Transparent proxying support.
421da177e4SLinus Torvalds  *		Keith Owens	:	RFC1191 correction for 4.2BSD based
431da177e4SLinus Torvalds  *					path MTU bug.
441da177e4SLinus Torvalds  *		Thomas Quinot	:	ICMP Dest Unreach codes up to 15 are
451da177e4SLinus Torvalds  *					valid (RFC 1812).
461da177e4SLinus Torvalds  *		Andi Kleen	:	Check all packet lengths properly
471da177e4SLinus Torvalds  *					and moved all kfree_skb() up to
481da177e4SLinus Torvalds  *					icmp_rcv.
491da177e4SLinus Torvalds  *		Andi Kleen	:	Move the rate limit bookkeeping
501da177e4SLinus Torvalds  *					into the dest entry and use a token
511da177e4SLinus Torvalds  *					bucket filter (thanks to ANK). Make
521da177e4SLinus Torvalds  *					the rates sysctl configurable.
531da177e4SLinus Torvalds  *		Yu Tianli	:	Fixed two ugly bugs in icmp_send
541da177e4SLinus Torvalds  *					- IP option length was accounted wrongly
551da177e4SLinus Torvalds  *					- ICMP header length was not accounted
561da177e4SLinus Torvalds  *					  at all.
571da177e4SLinus Torvalds  *              Tristan Greaves :       Added sysctl option to ignore bogus
581da177e4SLinus Torvalds  *              			broadcast responses from broken routers.
591da177e4SLinus Torvalds  *
601da177e4SLinus Torvalds  * To Fix:
611da177e4SLinus Torvalds  *
621da177e4SLinus Torvalds  *	- Should use skb_pull() instead of all the manual checking.
631da177e4SLinus Torvalds  *	  This would also greatly simply some upper layer error handlers. --AK
641da177e4SLinus Torvalds  *
651da177e4SLinus Torvalds  */
661da177e4SLinus Torvalds 
671da177e4SLinus Torvalds #include <linux/module.h>
681da177e4SLinus Torvalds #include <linux/types.h>
691da177e4SLinus Torvalds #include <linux/jiffies.h>
701da177e4SLinus Torvalds #include <linux/kernel.h>
711da177e4SLinus Torvalds #include <linux/fcntl.h>
721da177e4SLinus Torvalds #include <linux/socket.h>
731da177e4SLinus Torvalds #include <linux/in.h>
741da177e4SLinus Torvalds #include <linux/inet.h>
7514c85021SArnaldo Carvalho de Melo #include <linux/inetdevice.h>
761da177e4SLinus Torvalds #include <linux/netdevice.h>
771da177e4SLinus Torvalds #include <linux/string.h>
781da177e4SLinus Torvalds #include <linux/netfilter_ipv4.h>
791da177e4SLinus Torvalds #include <net/snmp.h>
801da177e4SLinus Torvalds #include <net/ip.h>
811da177e4SLinus Torvalds #include <net/route.h>
821da177e4SLinus Torvalds #include <net/protocol.h>
831da177e4SLinus Torvalds #include <net/icmp.h>
841da177e4SLinus Torvalds #include <net/tcp.h>
851da177e4SLinus Torvalds #include <net/udp.h>
861da177e4SLinus Torvalds #include <net/raw.h>
871da177e4SLinus Torvalds #include <linux/skbuff.h>
881da177e4SLinus Torvalds #include <net/sock.h>
891da177e4SLinus Torvalds #include <linux/errno.h>
901da177e4SLinus Torvalds #include <linux/timer.h>
911da177e4SLinus Torvalds #include <linux/init.h>
921da177e4SLinus Torvalds #include <asm/system.h>
931da177e4SLinus Torvalds #include <asm/uaccess.h>
941da177e4SLinus Torvalds #include <net/checksum.h>
951da177e4SLinus Torvalds 
961da177e4SLinus Torvalds /*
971da177e4SLinus Torvalds  *	Build xmit assembly blocks
981da177e4SLinus Torvalds  */
991da177e4SLinus Torvalds 
1001da177e4SLinus Torvalds struct icmp_bxm {
1011da177e4SLinus Torvalds 	struct sk_buff *skb;
1021da177e4SLinus Torvalds 	int offset;
1031da177e4SLinus Torvalds 	int data_len;
1041da177e4SLinus Torvalds 
1051da177e4SLinus Torvalds 	struct {
1061da177e4SLinus Torvalds 		struct icmphdr icmph;
107b03d73e3SAl Viro 		__be32	       times[3];
1081da177e4SLinus Torvalds 	} data;
1091da177e4SLinus Torvalds 	int head_len;
1101da177e4SLinus Torvalds 	struct ip_options replyopts;
1111da177e4SLinus Torvalds 	unsigned char  optbuf[40];
1121da177e4SLinus Torvalds };
1131da177e4SLinus Torvalds 
1141da177e4SLinus Torvalds /*
1151da177e4SLinus Torvalds  *	Statistics
1161da177e4SLinus Torvalds  */
117ba89966cSEric Dumazet DEFINE_SNMP_STAT(struct icmp_mib, icmp_statistics) __read_mostly;
1181da177e4SLinus Torvalds 
1191da177e4SLinus Torvalds /* An array of errno for error messages from dest unreach. */
1201da177e4SLinus Torvalds /* RFC 1122: 3.2.2.1 States that NET_UNREACH, HOST_UNREACH and SR_FAILED MUST be considered 'transient errs'. */
1211da177e4SLinus Torvalds 
1221da177e4SLinus Torvalds struct icmp_err icmp_err_convert[] = {
1231da177e4SLinus Torvalds 	{
1241da177e4SLinus Torvalds 		.errno = ENETUNREACH,	/* ICMP_NET_UNREACH */
1251da177e4SLinus Torvalds 		.fatal = 0,
1261da177e4SLinus Torvalds 	},
1271da177e4SLinus Torvalds 	{
1281da177e4SLinus Torvalds 		.errno = EHOSTUNREACH,	/* ICMP_HOST_UNREACH */
1291da177e4SLinus Torvalds 		.fatal = 0,
1301da177e4SLinus Torvalds 	},
1311da177e4SLinus Torvalds 	{
1321da177e4SLinus Torvalds 		.errno = ENOPROTOOPT	/* ICMP_PROT_UNREACH */,
1331da177e4SLinus Torvalds 		.fatal = 1,
1341da177e4SLinus Torvalds 	},
1351da177e4SLinus Torvalds 	{
1361da177e4SLinus Torvalds 		.errno = ECONNREFUSED,	/* ICMP_PORT_UNREACH */
1371da177e4SLinus Torvalds 		.fatal = 1,
1381da177e4SLinus Torvalds 	},
1391da177e4SLinus Torvalds 	{
1401da177e4SLinus Torvalds 		.errno = EMSGSIZE,	/* ICMP_FRAG_NEEDED */
1411da177e4SLinus Torvalds 		.fatal = 0,
1421da177e4SLinus Torvalds 	},
1431da177e4SLinus Torvalds 	{
1441da177e4SLinus Torvalds 		.errno = EOPNOTSUPP,	/* ICMP_SR_FAILED */
1451da177e4SLinus Torvalds 		.fatal = 0,
1461da177e4SLinus Torvalds 	},
1471da177e4SLinus Torvalds 	{
1481da177e4SLinus Torvalds 		.errno = ENETUNREACH,	/* ICMP_NET_UNKNOWN */
1491da177e4SLinus Torvalds 		.fatal = 1,
1501da177e4SLinus Torvalds 	},
1511da177e4SLinus Torvalds 	{
1521da177e4SLinus Torvalds 		.errno = EHOSTDOWN,	/* ICMP_HOST_UNKNOWN */
1531da177e4SLinus Torvalds 		.fatal = 1,
1541da177e4SLinus Torvalds 	},
1551da177e4SLinus Torvalds 	{
1561da177e4SLinus Torvalds 		.errno = ENONET,	/* ICMP_HOST_ISOLATED */
1571da177e4SLinus Torvalds 		.fatal = 1,
1581da177e4SLinus Torvalds 	},
1591da177e4SLinus Torvalds 	{
1601da177e4SLinus Torvalds 		.errno = ENETUNREACH,	/* ICMP_NET_ANO	*/
1611da177e4SLinus Torvalds 		.fatal = 1,
1621da177e4SLinus Torvalds 	},
1631da177e4SLinus Torvalds 	{
1641da177e4SLinus Torvalds 		.errno = EHOSTUNREACH,	/* ICMP_HOST_ANO */
1651da177e4SLinus Torvalds 		.fatal = 1,
1661da177e4SLinus Torvalds 	},
1671da177e4SLinus Torvalds 	{
1681da177e4SLinus Torvalds 		.errno = ENETUNREACH,	/* ICMP_NET_UNR_TOS */
1691da177e4SLinus Torvalds 		.fatal = 0,
1701da177e4SLinus Torvalds 	},
1711da177e4SLinus Torvalds 	{
1721da177e4SLinus Torvalds 		.errno = EHOSTUNREACH,	/* ICMP_HOST_UNR_TOS */
1731da177e4SLinus Torvalds 		.fatal = 0,
1741da177e4SLinus Torvalds 	},
1751da177e4SLinus Torvalds 	{
1761da177e4SLinus Torvalds 		.errno = EHOSTUNREACH,	/* ICMP_PKT_FILTERED */
1771da177e4SLinus Torvalds 		.fatal = 1,
1781da177e4SLinus Torvalds 	},
1791da177e4SLinus Torvalds 	{
1801da177e4SLinus Torvalds 		.errno = EHOSTUNREACH,	/* ICMP_PREC_VIOLATION */
1811da177e4SLinus Torvalds 		.fatal = 1,
1821da177e4SLinus Torvalds 	},
1831da177e4SLinus Torvalds 	{
1841da177e4SLinus Torvalds 		.errno = EHOSTUNREACH,	/* ICMP_PREC_CUTOFF */
1851da177e4SLinus Torvalds 		.fatal = 1,
1861da177e4SLinus Torvalds 	},
1871da177e4SLinus Torvalds };
1881da177e4SLinus Torvalds 
1891da177e4SLinus Torvalds /* Control parameters for ECHO replies. */
190ab32ea5dSBrian Haley int sysctl_icmp_echo_ignore_all __read_mostly;
191ab32ea5dSBrian Haley int sysctl_icmp_echo_ignore_broadcasts __read_mostly = 1;
1921da177e4SLinus Torvalds 
1931da177e4SLinus Torvalds /* Control parameter - ignore bogus broadcast responses? */
194ab32ea5dSBrian Haley int sysctl_icmp_ignore_bogus_error_responses __read_mostly = 1;
1951da177e4SLinus Torvalds 
1961da177e4SLinus Torvalds /*
1971da177e4SLinus Torvalds  * 	Configurable global rate limit.
1981da177e4SLinus Torvalds  *
1991da177e4SLinus Torvalds  *	ratelimit defines tokens/packet consumed for dst->rate_token bucket
2001da177e4SLinus Torvalds  *	ratemask defines which icmp types are ratelimited by setting
2011da177e4SLinus Torvalds  * 	it's bit position.
2021da177e4SLinus Torvalds  *
2031da177e4SLinus Torvalds  *	default:
2041da177e4SLinus Torvalds  *	dest unreachable (3), source quench (4),
2051da177e4SLinus Torvalds  *	time exceeded (11), parameter problem (12)
2061da177e4SLinus Torvalds  */
2071da177e4SLinus Torvalds 
208ab32ea5dSBrian Haley int sysctl_icmp_ratelimit __read_mostly = 1 * HZ;
209ab32ea5dSBrian Haley int sysctl_icmp_ratemask __read_mostly = 0x1818;
210ab32ea5dSBrian Haley int sysctl_icmp_errors_use_inbound_ifaddr __read_mostly;
2111da177e4SLinus Torvalds 
2121da177e4SLinus Torvalds /*
2131da177e4SLinus Torvalds  *	ICMP control array. This specifies what to do with each ICMP.
2141da177e4SLinus Torvalds  */
2151da177e4SLinus Torvalds 
2161da177e4SLinus Torvalds struct icmp_control {
2171da177e4SLinus Torvalds 	int output_entry;	/* Field for increment on output */
2181da177e4SLinus Torvalds 	int input_entry;	/* Field for increment on input */
2191da177e4SLinus Torvalds 	void (*handler)(struct sk_buff *skb);
2201da177e4SLinus Torvalds 	short   error;		/* This ICMP is classed as an error message */
2211da177e4SLinus Torvalds };
2221da177e4SLinus Torvalds 
2239b5b5cffSArjan van de Ven static const struct icmp_control icmp_pointers[NR_ICMP_TYPES+1];
2241da177e4SLinus Torvalds 
2251da177e4SLinus Torvalds /*
2261da177e4SLinus Torvalds  *	The ICMP socket(s). This is the most convenient way to flow control
2271da177e4SLinus Torvalds  *	our ICMP output as well as maintain a clean interface throughout
2281da177e4SLinus Torvalds  *	all layers. All Socketless IP sends will soon be gone.
2291da177e4SLinus Torvalds  *
2301da177e4SLinus Torvalds  *	On SMP we have one ICMP socket per-cpu.
2311da177e4SLinus Torvalds  */
2321da177e4SLinus Torvalds static DEFINE_PER_CPU(struct socket *, __icmp_socket) = NULL;
2331da177e4SLinus Torvalds #define icmp_socket	__get_cpu_var(__icmp_socket)
2341da177e4SLinus Torvalds 
2351da177e4SLinus Torvalds static __inline__ int icmp_xmit_lock(void)
2361da177e4SLinus Torvalds {
2371da177e4SLinus Torvalds 	local_bh_disable();
2381da177e4SLinus Torvalds 
2391da177e4SLinus Torvalds 	if (unlikely(!spin_trylock(&icmp_socket->sk->sk_lock.slock))) {
2401da177e4SLinus Torvalds 		/* This can happen if the output path signals a
2411da177e4SLinus Torvalds 		 * dst_link_failure() for an outgoing ICMP packet.
2421da177e4SLinus Torvalds 		 */
2431da177e4SLinus Torvalds 		local_bh_enable();
2441da177e4SLinus Torvalds 		return 1;
2451da177e4SLinus Torvalds 	}
2461da177e4SLinus Torvalds 	return 0;
2471da177e4SLinus Torvalds }
2481da177e4SLinus Torvalds 
2491da177e4SLinus Torvalds static void icmp_xmit_unlock(void)
2501da177e4SLinus Torvalds {
2511da177e4SLinus Torvalds 	spin_unlock_bh(&icmp_socket->sk->sk_lock.slock);
2521da177e4SLinus Torvalds }
2531da177e4SLinus Torvalds 
2541da177e4SLinus Torvalds /*
2551da177e4SLinus Torvalds  *	Send an ICMP frame.
2561da177e4SLinus Torvalds  */
2571da177e4SLinus Torvalds 
2581da177e4SLinus Torvalds /*
2591da177e4SLinus Torvalds  *	Check transmit rate limitation for given message.
2601da177e4SLinus Torvalds  *	The rate information is held in the destination cache now.
2611da177e4SLinus Torvalds  *	This function is generic and could be used for other purposes
2621da177e4SLinus Torvalds  *	too. It uses a Token bucket filter as suggested by Alexey Kuznetsov.
2631da177e4SLinus Torvalds  *
2641da177e4SLinus Torvalds  *	Note that the same dst_entry fields are modified by functions in
2651da177e4SLinus Torvalds  *	route.c too, but these work for packet destinations while xrlim_allow
2661da177e4SLinus Torvalds  *	works for icmp destinations. This means the rate limiting information
2671da177e4SLinus Torvalds  *	for one "ip object" is shared - and these ICMPs are twice limited:
2681da177e4SLinus Torvalds  *	by source and by destination.
2691da177e4SLinus Torvalds  *
2701da177e4SLinus Torvalds  *	RFC 1812: 4.3.2.8 SHOULD be able to limit error message rate
2711da177e4SLinus Torvalds  *			  SHOULD allow setting of rate limits
2721da177e4SLinus Torvalds  *
2731da177e4SLinus Torvalds  * 	Shared between ICMPv4 and ICMPv6.
2741da177e4SLinus Torvalds  */
2751da177e4SLinus Torvalds #define XRLIM_BURST_FACTOR 6
2761da177e4SLinus Torvalds int xrlim_allow(struct dst_entry *dst, int timeout)
2771da177e4SLinus Torvalds {
2781da177e4SLinus Torvalds 	unsigned long now;
2791da177e4SLinus Torvalds 	int rc = 0;
2801da177e4SLinus Torvalds 
2811da177e4SLinus Torvalds 	now = jiffies;
2821da177e4SLinus Torvalds 	dst->rate_tokens += now - dst->rate_last;
2831da177e4SLinus Torvalds 	dst->rate_last = now;
2841da177e4SLinus Torvalds 	if (dst->rate_tokens > XRLIM_BURST_FACTOR * timeout)
2851da177e4SLinus Torvalds 		dst->rate_tokens = XRLIM_BURST_FACTOR * timeout;
2861da177e4SLinus Torvalds 	if (dst->rate_tokens >= timeout) {
2871da177e4SLinus Torvalds 		dst->rate_tokens -= timeout;
2881da177e4SLinus Torvalds 		rc = 1;
2891da177e4SLinus Torvalds 	}
2901da177e4SLinus Torvalds 	return rc;
2911da177e4SLinus Torvalds }
2921da177e4SLinus Torvalds 
2931da177e4SLinus Torvalds static inline int icmpv4_xrlim_allow(struct rtable *rt, int type, int code)
2941da177e4SLinus Torvalds {
2951da177e4SLinus Torvalds 	struct dst_entry *dst = &rt->u.dst;
2961da177e4SLinus Torvalds 	int rc = 1;
2971da177e4SLinus Torvalds 
2981da177e4SLinus Torvalds 	if (type > NR_ICMP_TYPES)
2991da177e4SLinus Torvalds 		goto out;
3001da177e4SLinus Torvalds 
3011da177e4SLinus Torvalds 	/* Don't limit PMTU discovery. */
3021da177e4SLinus Torvalds 	if (type == ICMP_DEST_UNREACH && code == ICMP_FRAG_NEEDED)
3031da177e4SLinus Torvalds 		goto out;
3041da177e4SLinus Torvalds 
3051da177e4SLinus Torvalds 	/* No rate limit on loopback */
3061da177e4SLinus Torvalds 	if (dst->dev && (dst->dev->flags&IFF_LOOPBACK))
3071da177e4SLinus Torvalds  		goto out;
3081da177e4SLinus Torvalds 
3091da177e4SLinus Torvalds 	/* Limit if icmp type is enabled in ratemask. */
3101da177e4SLinus Torvalds 	if ((1 << type) & sysctl_icmp_ratemask)
3111da177e4SLinus Torvalds 		rc = xrlim_allow(dst, sysctl_icmp_ratelimit);
3121da177e4SLinus Torvalds out:
3131da177e4SLinus Torvalds 	return rc;
3141da177e4SLinus Torvalds }
3151da177e4SLinus Torvalds 
3161da177e4SLinus Torvalds /*
3171da177e4SLinus Torvalds  *	Maintain the counters used in the SNMP statistics for outgoing ICMP
3181da177e4SLinus Torvalds  */
3191da177e4SLinus Torvalds static void icmp_out_count(int type)
3201da177e4SLinus Torvalds {
3211da177e4SLinus Torvalds 	if (type <= NR_ICMP_TYPES) {
3221da177e4SLinus Torvalds 		ICMP_INC_STATS(icmp_pointers[type].output_entry);
3231da177e4SLinus Torvalds 		ICMP_INC_STATS(ICMP_MIB_OUTMSGS);
3241da177e4SLinus Torvalds 	}
3251da177e4SLinus Torvalds }
3261da177e4SLinus Torvalds 
3271da177e4SLinus Torvalds /*
3281da177e4SLinus Torvalds  *	Checksum each fragment, and on the first include the headers and final
3291da177e4SLinus Torvalds  *	checksum.
3301da177e4SLinus Torvalds  */
3311da177e4SLinus Torvalds static int icmp_glue_bits(void *from, char *to, int offset, int len, int odd,
3321da177e4SLinus Torvalds 			  struct sk_buff *skb)
3331da177e4SLinus Torvalds {
3341da177e4SLinus Torvalds 	struct icmp_bxm *icmp_param = (struct icmp_bxm *)from;
335*5f92a738SAl Viro 	__wsum csum;
3361da177e4SLinus Torvalds 
3371da177e4SLinus Torvalds 	csum = skb_copy_and_csum_bits(icmp_param->skb,
3381da177e4SLinus Torvalds 				      icmp_param->offset + offset,
3391da177e4SLinus Torvalds 				      to, len, 0);
3401da177e4SLinus Torvalds 
3411da177e4SLinus Torvalds 	skb->csum = csum_block_add(skb->csum, csum, odd);
3421da177e4SLinus Torvalds 	if (icmp_pointers[icmp_param->data.icmph.type].error)
3431da177e4SLinus Torvalds 		nf_ct_attach(skb, icmp_param->skb);
3441da177e4SLinus Torvalds 	return 0;
3451da177e4SLinus Torvalds }
3461da177e4SLinus Torvalds 
3471da177e4SLinus Torvalds static void icmp_push_reply(struct icmp_bxm *icmp_param,
3481da177e4SLinus Torvalds 			    struct ipcm_cookie *ipc, struct rtable *rt)
3491da177e4SLinus Torvalds {
3501da177e4SLinus Torvalds 	struct sk_buff *skb;
3511da177e4SLinus Torvalds 
352cb94c62cSPatrick McHardy 	if (ip_append_data(icmp_socket->sk, icmp_glue_bits, icmp_param,
3531da177e4SLinus Torvalds 		           icmp_param->data_len+icmp_param->head_len,
3541da177e4SLinus Torvalds 		           icmp_param->head_len,
355cb94c62cSPatrick McHardy 		           ipc, rt, MSG_DONTWAIT) < 0)
356cb94c62cSPatrick McHardy 		ip_flush_pending_frames(icmp_socket->sk);
357cb94c62cSPatrick McHardy 	else if ((skb = skb_peek(&icmp_socket->sk->sk_write_queue)) != NULL) {
3581da177e4SLinus Torvalds 		struct icmphdr *icmph = skb->h.icmph;
359d3bc23e7SAl Viro 		__wsum csum = 0;
3601da177e4SLinus Torvalds 		struct sk_buff *skb1;
3611da177e4SLinus Torvalds 
3621da177e4SLinus Torvalds 		skb_queue_walk(&icmp_socket->sk->sk_write_queue, skb1) {
3631da177e4SLinus Torvalds 			csum = csum_add(csum, skb1->csum);
3641da177e4SLinus Torvalds 		}
3651da177e4SLinus Torvalds 		csum = csum_partial_copy_nocheck((void *)&icmp_param->data,
3661da177e4SLinus Torvalds 						 (char *)icmph,
3671da177e4SLinus Torvalds 						 icmp_param->head_len, csum);
3681da177e4SLinus Torvalds 		icmph->checksum = csum_fold(csum);
3691da177e4SLinus Torvalds 		skb->ip_summed = CHECKSUM_NONE;
3701da177e4SLinus Torvalds 		ip_push_pending_frames(icmp_socket->sk);
3711da177e4SLinus Torvalds 	}
3721da177e4SLinus Torvalds }
3731da177e4SLinus Torvalds 
3741da177e4SLinus Torvalds /*
3751da177e4SLinus Torvalds  *	Driving logic for building and sending ICMP messages.
3761da177e4SLinus Torvalds  */
3771da177e4SLinus Torvalds 
3781da177e4SLinus Torvalds static void icmp_reply(struct icmp_bxm *icmp_param, struct sk_buff *skb)
3791da177e4SLinus Torvalds {
3801da177e4SLinus Torvalds 	struct sock *sk = icmp_socket->sk;
3811da177e4SLinus Torvalds 	struct inet_sock *inet = inet_sk(sk);
3821da177e4SLinus Torvalds 	struct ipcm_cookie ipc;
3831da177e4SLinus Torvalds 	struct rtable *rt = (struct rtable *)skb->dst;
3843ca3c68eSAl Viro 	__be32 daddr;
3851da177e4SLinus Torvalds 
3861da177e4SLinus Torvalds 	if (ip_options_echo(&icmp_param->replyopts, skb))
387f00c401bSHorms 		return;
3881da177e4SLinus Torvalds 
3891da177e4SLinus Torvalds 	if (icmp_xmit_lock())
3901da177e4SLinus Torvalds 		return;
3911da177e4SLinus Torvalds 
3921da177e4SLinus Torvalds 	icmp_param->data.icmph.checksum = 0;
3931da177e4SLinus Torvalds 	icmp_out_count(icmp_param->data.icmph.type);
3941da177e4SLinus Torvalds 
3951da177e4SLinus Torvalds 	inet->tos = skb->nh.iph->tos;
3961da177e4SLinus Torvalds 	daddr = ipc.addr = rt->rt_src;
3971da177e4SLinus Torvalds 	ipc.opt = NULL;
3981da177e4SLinus Torvalds 	if (icmp_param->replyopts.optlen) {
3991da177e4SLinus Torvalds 		ipc.opt = &icmp_param->replyopts;
4001da177e4SLinus Torvalds 		if (ipc.opt->srr)
4011da177e4SLinus Torvalds 			daddr = icmp_param->replyopts.faddr;
4021da177e4SLinus Torvalds 	}
4031da177e4SLinus Torvalds 	{
4041da177e4SLinus Torvalds 		struct flowi fl = { .nl_u = { .ip4_u =
4051da177e4SLinus Torvalds 					      { .daddr = daddr,
4061da177e4SLinus Torvalds 						.saddr = rt->rt_spec_dst,
4071da177e4SLinus Torvalds 						.tos = RT_TOS(skb->nh.iph->tos) } },
4081da177e4SLinus Torvalds 				    .proto = IPPROTO_ICMP };
409beb8d13bSVenkat Yekkirala 		security_skb_classify_flow(skb, &fl);
4101da177e4SLinus Torvalds 		if (ip_route_output_key(&rt, &fl))
4111da177e4SLinus Torvalds 			goto out_unlock;
4121da177e4SLinus Torvalds 	}
4131da177e4SLinus Torvalds 	if (icmpv4_xrlim_allow(rt, icmp_param->data.icmph.type,
4141da177e4SLinus Torvalds 			       icmp_param->data.icmph.code))
4151da177e4SLinus Torvalds 		icmp_push_reply(icmp_param, &ipc, rt);
4161da177e4SLinus Torvalds 	ip_rt_put(rt);
4171da177e4SLinus Torvalds out_unlock:
4181da177e4SLinus Torvalds 	icmp_xmit_unlock();
4191da177e4SLinus Torvalds }
4201da177e4SLinus Torvalds 
4211da177e4SLinus Torvalds 
4221da177e4SLinus Torvalds /*
4231da177e4SLinus Torvalds  *	Send an ICMP message in response to a situation
4241da177e4SLinus Torvalds  *
4251da177e4SLinus Torvalds  *	RFC 1122: 3.2.2	MUST send at least the IP header and 8 bytes of header.
4261da177e4SLinus Torvalds  *		  MAY send more (we do).
4271da177e4SLinus Torvalds  *			MUST NOT change this header information.
4281da177e4SLinus Torvalds  *			MUST NOT reply to a multicast/broadcast IP address.
4291da177e4SLinus Torvalds  *			MUST NOT reply to a multicast/broadcast MAC address.
4301da177e4SLinus Torvalds  *			MUST reply to only the first fragment.
4311da177e4SLinus Torvalds  */
4321da177e4SLinus Torvalds 
433e4883014SAl Viro void icmp_send(struct sk_buff *skb_in, int type, int code, __be32 info)
4341da177e4SLinus Torvalds {
4351da177e4SLinus Torvalds 	struct iphdr *iph;
4361da177e4SLinus Torvalds 	int room;
4371da177e4SLinus Torvalds 	struct icmp_bxm icmp_param;
4381da177e4SLinus Torvalds 	struct rtable *rt = (struct rtable *)skb_in->dst;
4391da177e4SLinus Torvalds 	struct ipcm_cookie ipc;
440a61ced5dSAl Viro 	__be32 saddr;
4411da177e4SLinus Torvalds 	u8  tos;
4421da177e4SLinus Torvalds 
4431da177e4SLinus Torvalds 	if (!rt)
4441da177e4SLinus Torvalds 		goto out;
4451da177e4SLinus Torvalds 
4461da177e4SLinus Torvalds 	/*
4471da177e4SLinus Torvalds 	 *	Find the original header. It is expected to be valid, of course.
4481da177e4SLinus Torvalds 	 *	Check this, icmp_send is called from the most obscure devices
4491da177e4SLinus Torvalds 	 *	sometimes.
4501da177e4SLinus Torvalds 	 */
4511da177e4SLinus Torvalds 	iph = skb_in->nh.iph;
4521da177e4SLinus Torvalds 
4531da177e4SLinus Torvalds 	if ((u8 *)iph < skb_in->head || (u8 *)(iph + 1) > skb_in->tail)
4541da177e4SLinus Torvalds 		goto out;
4551da177e4SLinus Torvalds 
4561da177e4SLinus Torvalds 	/*
4571da177e4SLinus Torvalds 	 *	No replies to physical multicast/broadcast
4581da177e4SLinus Torvalds 	 */
4591da177e4SLinus Torvalds 	if (skb_in->pkt_type != PACKET_HOST)
4601da177e4SLinus Torvalds 		goto out;
4611da177e4SLinus Torvalds 
4621da177e4SLinus Torvalds 	/*
4631da177e4SLinus Torvalds 	 *	Now check at the protocol level
4641da177e4SLinus Torvalds 	 */
4651da177e4SLinus Torvalds 	if (rt->rt_flags & (RTCF_BROADCAST | RTCF_MULTICAST))
4661da177e4SLinus Torvalds 		goto out;
4671da177e4SLinus Torvalds 
4681da177e4SLinus Torvalds 	/*
4691da177e4SLinus Torvalds 	 *	Only reply to fragment 0. We byte re-order the constant
4701da177e4SLinus Torvalds 	 *	mask for efficiency.
4711da177e4SLinus Torvalds 	 */
4721da177e4SLinus Torvalds 	if (iph->frag_off & htons(IP_OFFSET))
4731da177e4SLinus Torvalds 		goto out;
4741da177e4SLinus Torvalds 
4751da177e4SLinus Torvalds 	/*
4761da177e4SLinus Torvalds 	 *	If we send an ICMP error to an ICMP error a mess would result..
4771da177e4SLinus Torvalds 	 */
4781da177e4SLinus Torvalds 	if (icmp_pointers[type].error) {
4791da177e4SLinus Torvalds 		/*
4801da177e4SLinus Torvalds 		 *	We are an error, check if we are replying to an
4811da177e4SLinus Torvalds 		 *	ICMP error
4821da177e4SLinus Torvalds 		 */
4831da177e4SLinus Torvalds 		if (iph->protocol == IPPROTO_ICMP) {
4841da177e4SLinus Torvalds 			u8 _inner_type, *itp;
4851da177e4SLinus Torvalds 
4861da177e4SLinus Torvalds 			itp = skb_header_pointer(skb_in,
4871da177e4SLinus Torvalds 						 skb_in->nh.raw +
4881da177e4SLinus Torvalds 						 (iph->ihl << 2) +
4891da177e4SLinus Torvalds 						 offsetof(struct icmphdr,
4901da177e4SLinus Torvalds 							  type) -
4911da177e4SLinus Torvalds 						 skb_in->data,
4921da177e4SLinus Torvalds 						 sizeof(_inner_type),
4931da177e4SLinus Torvalds 						 &_inner_type);
4941da177e4SLinus Torvalds 			if (itp == NULL)
4951da177e4SLinus Torvalds 				goto out;
4961da177e4SLinus Torvalds 
4971da177e4SLinus Torvalds 			/*
4981da177e4SLinus Torvalds 			 *	Assume any unknown ICMP type is an error. This
4991da177e4SLinus Torvalds 			 *	isn't specified by the RFC, but think about it..
5001da177e4SLinus Torvalds 			 */
5011da177e4SLinus Torvalds 			if (*itp > NR_ICMP_TYPES ||
5021da177e4SLinus Torvalds 			    icmp_pointers[*itp].error)
5031da177e4SLinus Torvalds 				goto out;
5041da177e4SLinus Torvalds 		}
5051da177e4SLinus Torvalds 	}
5061da177e4SLinus Torvalds 
5071da177e4SLinus Torvalds 	if (icmp_xmit_lock())
5081da177e4SLinus Torvalds 		return;
5091da177e4SLinus Torvalds 
5101da177e4SLinus Torvalds 	/*
5111da177e4SLinus Torvalds 	 *	Construct source address and options.
5121da177e4SLinus Torvalds 	 */
5131da177e4SLinus Torvalds 
5141da177e4SLinus Torvalds 	saddr = iph->daddr;
5151c2fb7f9SJ. Simonetti 	if (!(rt->rt_flags & RTCF_LOCAL)) {
5161c2fb7f9SJ. Simonetti 		if (sysctl_icmp_errors_use_inbound_ifaddr)
5171c2fb7f9SJ. Simonetti 			saddr = inet_select_addr(skb_in->dev, 0, RT_SCOPE_LINK);
5181c2fb7f9SJ. Simonetti 		else
5191da177e4SLinus Torvalds 			saddr = 0;
5201c2fb7f9SJ. Simonetti 	}
5211da177e4SLinus Torvalds 
5221da177e4SLinus Torvalds 	tos = icmp_pointers[type].error ? ((iph->tos & IPTOS_TOS_MASK) |
5231da177e4SLinus Torvalds 					   IPTOS_PREC_INTERNETCONTROL) :
5241da177e4SLinus Torvalds 					  iph->tos;
5251da177e4SLinus Torvalds 
5261da177e4SLinus Torvalds 	if (ip_options_echo(&icmp_param.replyopts, skb_in))
527fa60cf7fSHerbert Xu 		goto out_unlock;
5281da177e4SLinus Torvalds 
5291da177e4SLinus Torvalds 
5301da177e4SLinus Torvalds 	/*
5311da177e4SLinus Torvalds 	 *	Prepare data for ICMP header.
5321da177e4SLinus Torvalds 	 */
5331da177e4SLinus Torvalds 
5341da177e4SLinus Torvalds 	icmp_param.data.icmph.type	 = type;
5351da177e4SLinus Torvalds 	icmp_param.data.icmph.code	 = code;
5361da177e4SLinus Torvalds 	icmp_param.data.icmph.un.gateway = info;
5371da177e4SLinus Torvalds 	icmp_param.data.icmph.checksum	 = 0;
5381da177e4SLinus Torvalds 	icmp_param.skb	  = skb_in;
5391da177e4SLinus Torvalds 	icmp_param.offset = skb_in->nh.raw - skb_in->data;
5401da177e4SLinus Torvalds 	icmp_out_count(icmp_param.data.icmph.type);
5411da177e4SLinus Torvalds 	inet_sk(icmp_socket->sk)->tos = tos;
5421da177e4SLinus Torvalds 	ipc.addr = iph->saddr;
5431da177e4SLinus Torvalds 	ipc.opt = &icmp_param.replyopts;
5441da177e4SLinus Torvalds 
5451da177e4SLinus Torvalds 	{
5461da177e4SLinus Torvalds 		struct flowi fl = {
5471da177e4SLinus Torvalds 			.nl_u = {
5481da177e4SLinus Torvalds 				.ip4_u = {
5491da177e4SLinus Torvalds 					.daddr = icmp_param.replyopts.srr ?
5501da177e4SLinus Torvalds 						icmp_param.replyopts.faddr :
5511da177e4SLinus Torvalds 						iph->saddr,
5521da177e4SLinus Torvalds 					.saddr = saddr,
5531da177e4SLinus Torvalds 					.tos = RT_TOS(tos)
5541da177e4SLinus Torvalds 				}
5551da177e4SLinus Torvalds 			},
5561da177e4SLinus Torvalds 			.proto = IPPROTO_ICMP,
5571da177e4SLinus Torvalds 			.uli_u = {
5581da177e4SLinus Torvalds 				.icmpt = {
5591da177e4SLinus Torvalds 					.type = type,
5601da177e4SLinus Torvalds 					.code = code
5611da177e4SLinus Torvalds 				}
5621da177e4SLinus Torvalds 			}
5631da177e4SLinus Torvalds 		};
564beb8d13bSVenkat Yekkirala 		security_skb_classify_flow(skb_in, &fl);
5651da177e4SLinus Torvalds 		if (ip_route_output_key(&rt, &fl))
5661da177e4SLinus Torvalds 			goto out_unlock;
5671da177e4SLinus Torvalds 	}
5681da177e4SLinus Torvalds 
5691da177e4SLinus Torvalds 	if (!icmpv4_xrlim_allow(rt, type, code))
5701da177e4SLinus Torvalds 		goto ende;
5711da177e4SLinus Torvalds 
5721da177e4SLinus Torvalds 	/* RFC says return as much as we can without exceeding 576 bytes. */
5731da177e4SLinus Torvalds 
5741da177e4SLinus Torvalds 	room = dst_mtu(&rt->u.dst);
5751da177e4SLinus Torvalds 	if (room > 576)
5761da177e4SLinus Torvalds 		room = 576;
5771da177e4SLinus Torvalds 	room -= sizeof(struct iphdr) + icmp_param.replyopts.optlen;
5781da177e4SLinus Torvalds 	room -= sizeof(struct icmphdr);
5791da177e4SLinus Torvalds 
5801da177e4SLinus Torvalds 	icmp_param.data_len = skb_in->len - icmp_param.offset;
5811da177e4SLinus Torvalds 	if (icmp_param.data_len > room)
5821da177e4SLinus Torvalds 		icmp_param.data_len = room;
5831da177e4SLinus Torvalds 	icmp_param.head_len = sizeof(struct icmphdr);
5841da177e4SLinus Torvalds 
5851da177e4SLinus Torvalds 	icmp_push_reply(&icmp_param, &ipc, rt);
5861da177e4SLinus Torvalds ende:
5871da177e4SLinus Torvalds 	ip_rt_put(rt);
5881da177e4SLinus Torvalds out_unlock:
5891da177e4SLinus Torvalds 	icmp_xmit_unlock();
5901da177e4SLinus Torvalds out:;
5911da177e4SLinus Torvalds }
5921da177e4SLinus Torvalds 
5931da177e4SLinus Torvalds 
5941da177e4SLinus Torvalds /*
5951da177e4SLinus Torvalds  *	Handle ICMP_DEST_UNREACH, ICMP_TIME_EXCEED, and ICMP_QUENCH.
5961da177e4SLinus Torvalds  */
5971da177e4SLinus Torvalds 
5981da177e4SLinus Torvalds static void icmp_unreach(struct sk_buff *skb)
5991da177e4SLinus Torvalds {
6001da177e4SLinus Torvalds 	struct iphdr *iph;
6011da177e4SLinus Torvalds 	struct icmphdr *icmph;
6021da177e4SLinus Torvalds 	int hash, protocol;
6031da177e4SLinus Torvalds 	struct net_protocol *ipprot;
6041da177e4SLinus Torvalds 	struct sock *raw_sk;
6051da177e4SLinus Torvalds 	u32 info = 0;
6061da177e4SLinus Torvalds 
6071da177e4SLinus Torvalds 	/*
6081da177e4SLinus Torvalds 	 *	Incomplete header ?
6091da177e4SLinus Torvalds 	 * 	Only checks for the IP header, there should be an
6101da177e4SLinus Torvalds 	 *	additional check for longer headers in upper levels.
6111da177e4SLinus Torvalds 	 */
6121da177e4SLinus Torvalds 
6131da177e4SLinus Torvalds 	if (!pskb_may_pull(skb, sizeof(struct iphdr)))
6141da177e4SLinus Torvalds 		goto out_err;
6151da177e4SLinus Torvalds 
6161da177e4SLinus Torvalds 	icmph = skb->h.icmph;
6171da177e4SLinus Torvalds 	iph   = (struct iphdr *)skb->data;
6181da177e4SLinus Torvalds 
6191da177e4SLinus Torvalds 	if (iph->ihl < 5) /* Mangled header, drop. */
6201da177e4SLinus Torvalds 		goto out_err;
6211da177e4SLinus Torvalds 
6221da177e4SLinus Torvalds 	if (icmph->type == ICMP_DEST_UNREACH) {
6231da177e4SLinus Torvalds 		switch (icmph->code & 15) {
6241da177e4SLinus Torvalds 		case ICMP_NET_UNREACH:
6251da177e4SLinus Torvalds 		case ICMP_HOST_UNREACH:
6261da177e4SLinus Torvalds 		case ICMP_PROT_UNREACH:
6271da177e4SLinus Torvalds 		case ICMP_PORT_UNREACH:
6281da177e4SLinus Torvalds 			break;
6291da177e4SLinus Torvalds 		case ICMP_FRAG_NEEDED:
6301da177e4SLinus Torvalds 			if (ipv4_config.no_pmtu_disc) {
63164ce2073SPatrick McHardy 				LIMIT_NETDEBUG(KERN_INFO "ICMP: %u.%u.%u.%u: "
6321da177e4SLinus Torvalds 							 "fragmentation needed "
6331da177e4SLinus Torvalds 							 "and DF set.\n",
63464ce2073SPatrick McHardy 					       NIPQUAD(iph->daddr));
6351da177e4SLinus Torvalds 			} else {
6361da177e4SLinus Torvalds 				info = ip_rt_frag_needed(iph,
6371da177e4SLinus Torvalds 						     ntohs(icmph->un.frag.mtu));
6381da177e4SLinus Torvalds 				if (!info)
6391da177e4SLinus Torvalds 					goto out;
6401da177e4SLinus Torvalds 			}
6411da177e4SLinus Torvalds 			break;
6421da177e4SLinus Torvalds 		case ICMP_SR_FAILED:
64364ce2073SPatrick McHardy 			LIMIT_NETDEBUG(KERN_INFO "ICMP: %u.%u.%u.%u: Source "
6441da177e4SLinus Torvalds 						 "Route Failed.\n",
64564ce2073SPatrick McHardy 				       NIPQUAD(iph->daddr));
6461da177e4SLinus Torvalds 			break;
6471da177e4SLinus Torvalds 		default:
6481da177e4SLinus Torvalds 			break;
6491da177e4SLinus Torvalds 		}
6501da177e4SLinus Torvalds 		if (icmph->code > NR_ICMP_UNREACH)
6511da177e4SLinus Torvalds 			goto out;
6521da177e4SLinus Torvalds 	} else if (icmph->type == ICMP_PARAMETERPROB)
6531da177e4SLinus Torvalds 		info = ntohl(icmph->un.gateway) >> 24;
6541da177e4SLinus Torvalds 
6551da177e4SLinus Torvalds 	/*
6561da177e4SLinus Torvalds 	 *	Throw it at our lower layers
6571da177e4SLinus Torvalds 	 *
6581da177e4SLinus Torvalds 	 *	RFC 1122: 3.2.2 MUST extract the protocol ID from the passed
6591da177e4SLinus Torvalds 	 *		  header.
6601da177e4SLinus Torvalds 	 *	RFC 1122: 3.2.2.1 MUST pass ICMP unreach messages to the
6611da177e4SLinus Torvalds 	 *		  transport layer.
6621da177e4SLinus Torvalds 	 *	RFC 1122: 3.2.2.2 MUST pass ICMP time expired messages to
6631da177e4SLinus Torvalds 	 *		  transport layer.
6641da177e4SLinus Torvalds 	 */
6651da177e4SLinus Torvalds 
6661da177e4SLinus Torvalds 	/*
6671da177e4SLinus Torvalds 	 *	Check the other end isnt violating RFC 1122. Some routers send
6681da177e4SLinus Torvalds 	 *	bogus responses to broadcast frames. If you see this message
6691da177e4SLinus Torvalds 	 *	first check your netmask matches at both ends, if it does then
6701da177e4SLinus Torvalds 	 *	get the other vendor to fix their kit.
6711da177e4SLinus Torvalds 	 */
6721da177e4SLinus Torvalds 
6731da177e4SLinus Torvalds 	if (!sysctl_icmp_ignore_bogus_error_responses &&
6741da177e4SLinus Torvalds 	    inet_addr_type(iph->daddr) == RTN_BROADCAST) {
6751da177e4SLinus Torvalds 		if (net_ratelimit())
6761da177e4SLinus Torvalds 			printk(KERN_WARNING "%u.%u.%u.%u sent an invalid ICMP "
6771da177e4SLinus Torvalds 					    "type %u, code %u "
6781da177e4SLinus Torvalds 					    "error to a broadcast: %u.%u.%u.%u on %s\n",
6791da177e4SLinus Torvalds 			       NIPQUAD(skb->nh.iph->saddr),
6801da177e4SLinus Torvalds 			       icmph->type, icmph->code,
6811da177e4SLinus Torvalds 			       NIPQUAD(iph->daddr),
6821da177e4SLinus Torvalds 			       skb->dev->name);
6831da177e4SLinus Torvalds 		goto out;
6841da177e4SLinus Torvalds 	}
6851da177e4SLinus Torvalds 
6861da177e4SLinus Torvalds 	/* Checkin full IP header plus 8 bytes of protocol to
6871da177e4SLinus Torvalds 	 * avoid additional coding at protocol handlers.
6881da177e4SLinus Torvalds 	 */
6891da177e4SLinus Torvalds 	if (!pskb_may_pull(skb, iph->ihl * 4 + 8))
6901da177e4SLinus Torvalds 		goto out;
6911da177e4SLinus Torvalds 
6921da177e4SLinus Torvalds 	iph = (struct iphdr *)skb->data;
6931da177e4SLinus Torvalds 	protocol = iph->protocol;
6941da177e4SLinus Torvalds 
6951da177e4SLinus Torvalds 	/*
6961da177e4SLinus Torvalds 	 *	Deliver ICMP message to raw sockets. Pretty useless feature?
6971da177e4SLinus Torvalds 	 */
6981da177e4SLinus Torvalds 
6991da177e4SLinus Torvalds 	/* Note: See raw.c and net/raw.h, RAWV4_HTABLE_SIZE==MAX_INET_PROTOS */
7001da177e4SLinus Torvalds 	hash = protocol & (MAX_INET_PROTOS - 1);
7011da177e4SLinus Torvalds 	read_lock(&raw_v4_lock);
7021da177e4SLinus Torvalds 	if ((raw_sk = sk_head(&raw_v4_htable[hash])) != NULL) {
7031da177e4SLinus Torvalds 		while ((raw_sk = __raw_v4_lookup(raw_sk, protocol, iph->daddr,
7041da177e4SLinus Torvalds 						 iph->saddr,
7051da177e4SLinus Torvalds 						 skb->dev->ifindex)) != NULL) {
7061da177e4SLinus Torvalds 			raw_err(raw_sk, skb, info);
7071da177e4SLinus Torvalds 			raw_sk = sk_next(raw_sk);
7081da177e4SLinus Torvalds 			iph = (struct iphdr *)skb->data;
7091da177e4SLinus Torvalds 		}
7101da177e4SLinus Torvalds 	}
7111da177e4SLinus Torvalds 	read_unlock(&raw_v4_lock);
7121da177e4SLinus Torvalds 
7131da177e4SLinus Torvalds 	rcu_read_lock();
7141da177e4SLinus Torvalds 	ipprot = rcu_dereference(inet_protos[hash]);
7151da177e4SLinus Torvalds 	if (ipprot && ipprot->err_handler)
7161da177e4SLinus Torvalds 		ipprot->err_handler(skb, info);
7171da177e4SLinus Torvalds 	rcu_read_unlock();
7181da177e4SLinus Torvalds 
7191da177e4SLinus Torvalds out:
7201da177e4SLinus Torvalds 	return;
7211da177e4SLinus Torvalds out_err:
7221da177e4SLinus Torvalds 	ICMP_INC_STATS_BH(ICMP_MIB_INERRORS);
7231da177e4SLinus Torvalds 	goto out;
7241da177e4SLinus Torvalds }
7251da177e4SLinus Torvalds 
7261da177e4SLinus Torvalds 
7271da177e4SLinus Torvalds /*
7281da177e4SLinus Torvalds  *	Handle ICMP_REDIRECT.
7291da177e4SLinus Torvalds  */
7301da177e4SLinus Torvalds 
7311da177e4SLinus Torvalds static void icmp_redirect(struct sk_buff *skb)
7321da177e4SLinus Torvalds {
7331da177e4SLinus Torvalds 	struct iphdr *iph;
7341da177e4SLinus Torvalds 
7351da177e4SLinus Torvalds 	if (skb->len < sizeof(struct iphdr))
7361da177e4SLinus Torvalds 		goto out_err;
7371da177e4SLinus Torvalds 
7381da177e4SLinus Torvalds 	/*
7391da177e4SLinus Torvalds 	 *	Get the copied header of the packet that caused the redirect
7401da177e4SLinus Torvalds 	 */
7411da177e4SLinus Torvalds 	if (!pskb_may_pull(skb, sizeof(struct iphdr)))
7421da177e4SLinus Torvalds 		goto out;
7431da177e4SLinus Torvalds 
7441da177e4SLinus Torvalds 	iph = (struct iphdr *)skb->data;
7451da177e4SLinus Torvalds 
7461da177e4SLinus Torvalds 	switch (skb->h.icmph->code & 7) {
7471da177e4SLinus Torvalds 	case ICMP_REDIR_NET:
7481da177e4SLinus Torvalds 	case ICMP_REDIR_NETTOS:
7491da177e4SLinus Torvalds 		/*
7501da177e4SLinus Torvalds 		 * As per RFC recommendations now handle it as a host redirect.
7511da177e4SLinus Torvalds 		 */
7521da177e4SLinus Torvalds 	case ICMP_REDIR_HOST:
7531da177e4SLinus Torvalds 	case ICMP_REDIR_HOSTTOS:
754f86502bfSDavid S. Miller 		ip_rt_redirect(skb->nh.iph->saddr, iph->daddr,
755f86502bfSDavid S. Miller 			       skb->h.icmph->un.gateway,
756cef2685eSIlia Sotnikov 			       iph->saddr, skb->dev);
7571da177e4SLinus Torvalds 		break;
7581da177e4SLinus Torvalds   	}
7591da177e4SLinus Torvalds out:
7601da177e4SLinus Torvalds 	return;
7611da177e4SLinus Torvalds out_err:
7621da177e4SLinus Torvalds 	ICMP_INC_STATS_BH(ICMP_MIB_INERRORS);
7631da177e4SLinus Torvalds 	goto out;
7641da177e4SLinus Torvalds }
7651da177e4SLinus Torvalds 
7661da177e4SLinus Torvalds /*
7671da177e4SLinus Torvalds  *	Handle ICMP_ECHO ("ping") requests.
7681da177e4SLinus Torvalds  *
7691da177e4SLinus Torvalds  *	RFC 1122: 3.2.2.6 MUST have an echo server that answers ICMP echo
7701da177e4SLinus Torvalds  *		  requests.
7711da177e4SLinus Torvalds  *	RFC 1122: 3.2.2.6 Data received in the ICMP_ECHO request MUST be
7721da177e4SLinus Torvalds  *		  included in the reply.
7731da177e4SLinus Torvalds  *	RFC 1812: 4.3.3.6 SHOULD have a config option for silently ignoring
7741da177e4SLinus Torvalds  *		  echo requests, MUST have default=NOT.
7751da177e4SLinus Torvalds  *	See also WRT handling of options once they are done and working.
7761da177e4SLinus Torvalds  */
7771da177e4SLinus Torvalds 
7781da177e4SLinus Torvalds static void icmp_echo(struct sk_buff *skb)
7791da177e4SLinus Torvalds {
7801da177e4SLinus Torvalds 	if (!sysctl_icmp_echo_ignore_all) {
7811da177e4SLinus Torvalds 		struct icmp_bxm icmp_param;
7821da177e4SLinus Torvalds 
7831da177e4SLinus Torvalds 		icmp_param.data.icmph	   = *skb->h.icmph;
7841da177e4SLinus Torvalds 		icmp_param.data.icmph.type = ICMP_ECHOREPLY;
7851da177e4SLinus Torvalds 		icmp_param.skb		   = skb;
7861da177e4SLinus Torvalds 		icmp_param.offset	   = 0;
7871da177e4SLinus Torvalds 		icmp_param.data_len	   = skb->len;
7881da177e4SLinus Torvalds 		icmp_param.head_len	   = sizeof(struct icmphdr);
7891da177e4SLinus Torvalds 		icmp_reply(&icmp_param, skb);
7901da177e4SLinus Torvalds 	}
7911da177e4SLinus Torvalds }
7921da177e4SLinus Torvalds 
7931da177e4SLinus Torvalds /*
7941da177e4SLinus Torvalds  *	Handle ICMP Timestamp requests.
7951da177e4SLinus Torvalds  *	RFC 1122: 3.2.2.8 MAY implement ICMP timestamp requests.
7961da177e4SLinus Torvalds  *		  SHOULD be in the kernel for minimum random latency.
7971da177e4SLinus Torvalds  *		  MUST be accurate to a few minutes.
7981da177e4SLinus Torvalds  *		  MUST be updated at least at 15Hz.
7991da177e4SLinus Torvalds  */
8001da177e4SLinus Torvalds static void icmp_timestamp(struct sk_buff *skb)
8011da177e4SLinus Torvalds {
8021da177e4SLinus Torvalds 	struct timeval tv;
8031da177e4SLinus Torvalds 	struct icmp_bxm icmp_param;
8041da177e4SLinus Torvalds 	/*
8051da177e4SLinus Torvalds 	 *	Too short.
8061da177e4SLinus Torvalds 	 */
8071da177e4SLinus Torvalds 	if (skb->len < 4)
8081da177e4SLinus Torvalds 		goto out_err;
8091da177e4SLinus Torvalds 
8101da177e4SLinus Torvalds 	/*
8111da177e4SLinus Torvalds 	 *	Fill in the current time as ms since midnight UT:
8121da177e4SLinus Torvalds 	 */
8131da177e4SLinus Torvalds 	do_gettimeofday(&tv);
8141da177e4SLinus Torvalds 	icmp_param.data.times[1] = htonl((tv.tv_sec % 86400) * 1000 +
8151da177e4SLinus Torvalds 					 tv.tv_usec / 1000);
8161da177e4SLinus Torvalds 	icmp_param.data.times[2] = icmp_param.data.times[1];
8171da177e4SLinus Torvalds 	if (skb_copy_bits(skb, 0, &icmp_param.data.times[0], 4))
8181da177e4SLinus Torvalds 		BUG();
8191da177e4SLinus Torvalds 	icmp_param.data.icmph	   = *skb->h.icmph;
8201da177e4SLinus Torvalds 	icmp_param.data.icmph.type = ICMP_TIMESTAMPREPLY;
8211da177e4SLinus Torvalds 	icmp_param.data.icmph.code = 0;
8221da177e4SLinus Torvalds 	icmp_param.skb		   = skb;
8231da177e4SLinus Torvalds 	icmp_param.offset	   = 0;
8241da177e4SLinus Torvalds 	icmp_param.data_len	   = 0;
8251da177e4SLinus Torvalds 	icmp_param.head_len	   = sizeof(struct icmphdr) + 12;
8261da177e4SLinus Torvalds 	icmp_reply(&icmp_param, skb);
8271da177e4SLinus Torvalds out:
8281da177e4SLinus Torvalds 	return;
8291da177e4SLinus Torvalds out_err:
8301da177e4SLinus Torvalds 	ICMP_INC_STATS_BH(ICMP_MIB_INERRORS);
8311da177e4SLinus Torvalds 	goto out;
8321da177e4SLinus Torvalds }
8331da177e4SLinus Torvalds 
8341da177e4SLinus Torvalds 
8351da177e4SLinus Torvalds /*
8361da177e4SLinus Torvalds  *	Handle ICMP_ADDRESS_MASK requests.  (RFC950)
8371da177e4SLinus Torvalds  *
8381da177e4SLinus Torvalds  * RFC1122 (3.2.2.9).  A host MUST only send replies to
8391da177e4SLinus Torvalds  * ADDRESS_MASK requests if it's been configured as an address mask
8401da177e4SLinus Torvalds  * agent.  Receiving a request doesn't constitute implicit permission to
8411da177e4SLinus Torvalds  * act as one. Of course, implementing this correctly requires (SHOULD)
8421da177e4SLinus Torvalds  * a way to turn the functionality on and off.  Another one for sysctl(),
8431da177e4SLinus Torvalds  * I guess. -- MS
8441da177e4SLinus Torvalds  *
8451da177e4SLinus Torvalds  * RFC1812 (4.3.3.9).	A router MUST implement it.
8461da177e4SLinus Torvalds  *			A router SHOULD have switch turning it on/off.
8471da177e4SLinus Torvalds  *		      	This switch MUST be ON by default.
8481da177e4SLinus Torvalds  *
8491da177e4SLinus Torvalds  * Gratuitous replies, zero-source replies are not implemented,
8501da177e4SLinus Torvalds  * that complies with RFC. DO NOT implement them!!! All the idea
8511da177e4SLinus Torvalds  * of broadcast addrmask replies as specified in RFC950 is broken.
8521da177e4SLinus Torvalds  * The problem is that it is not uncommon to have several prefixes
8531da177e4SLinus Torvalds  * on one physical interface. Moreover, addrmask agent can even be
8541da177e4SLinus Torvalds  * not aware of existing another prefixes.
8551da177e4SLinus Torvalds  * If source is zero, addrmask agent cannot choose correct prefix.
8561da177e4SLinus Torvalds  * Gratuitous mask announcements suffer from the same problem.
8571da177e4SLinus Torvalds  * RFC1812 explains it, but still allows to use ADDRMASK,
8581da177e4SLinus Torvalds  * that is pretty silly. --ANK
8591da177e4SLinus Torvalds  *
8601da177e4SLinus Torvalds  * All these rules are so bizarre, that I removed kernel addrmask
8611da177e4SLinus Torvalds  * support at all. It is wrong, it is obsolete, nobody uses it in
8621da177e4SLinus Torvalds  * any case. --ANK
8631da177e4SLinus Torvalds  *
8641da177e4SLinus Torvalds  * Furthermore you can do it with a usermode address agent program
8651da177e4SLinus Torvalds  * anyway...
8661da177e4SLinus Torvalds  */
8671da177e4SLinus Torvalds 
8681da177e4SLinus Torvalds static void icmp_address(struct sk_buff *skb)
8691da177e4SLinus Torvalds {
8701da177e4SLinus Torvalds #if 0
8711da177e4SLinus Torvalds 	if (net_ratelimit())
8721da177e4SLinus Torvalds 		printk(KERN_DEBUG "a guy asks for address mask. Who is it?\n");
8731da177e4SLinus Torvalds #endif
8741da177e4SLinus Torvalds }
8751da177e4SLinus Torvalds 
8761da177e4SLinus Torvalds /*
8771da177e4SLinus Torvalds  * RFC1812 (4.3.3.9).	A router SHOULD listen all replies, and complain
8781da177e4SLinus Torvalds  *			loudly if an inconsistency is found.
8791da177e4SLinus Torvalds  */
8801da177e4SLinus Torvalds 
8811da177e4SLinus Torvalds static void icmp_address_reply(struct sk_buff *skb)
8821da177e4SLinus Torvalds {
8831da177e4SLinus Torvalds 	struct rtable *rt = (struct rtable *)skb->dst;
8841da177e4SLinus Torvalds 	struct net_device *dev = skb->dev;
8851da177e4SLinus Torvalds 	struct in_device *in_dev;
8861da177e4SLinus Torvalds 	struct in_ifaddr *ifa;
8871da177e4SLinus Torvalds 
8881da177e4SLinus Torvalds 	if (skb->len < 4 || !(rt->rt_flags&RTCF_DIRECTSRC))
8891da177e4SLinus Torvalds 		goto out;
8901da177e4SLinus Torvalds 
8911da177e4SLinus Torvalds 	in_dev = in_dev_get(dev);
8921da177e4SLinus Torvalds 	if (!in_dev)
8931da177e4SLinus Torvalds 		goto out;
8941da177e4SLinus Torvalds 	rcu_read_lock();
8951da177e4SLinus Torvalds 	if (in_dev->ifa_list &&
8961da177e4SLinus Torvalds 	    IN_DEV_LOG_MARTIANS(in_dev) &&
8971da177e4SLinus Torvalds 	    IN_DEV_FORWARD(in_dev)) {
898a144ea4bSAl Viro 		__be32 _mask, *mp;
8991da177e4SLinus Torvalds 
9001da177e4SLinus Torvalds 		mp = skb_header_pointer(skb, 0, sizeof(_mask), &_mask);
90109a62660SKris Katterjohn 		BUG_ON(mp == NULL);
9021da177e4SLinus Torvalds 		for (ifa = in_dev->ifa_list; ifa; ifa = ifa->ifa_next) {
9031da177e4SLinus Torvalds 			if (*mp == ifa->ifa_mask &&
9041da177e4SLinus Torvalds 			    inet_ifa_match(rt->rt_src, ifa))
9051da177e4SLinus Torvalds 				break;
9061da177e4SLinus Torvalds 		}
9071da177e4SLinus Torvalds 		if (!ifa && net_ratelimit()) {
9081da177e4SLinus Torvalds 			printk(KERN_INFO "Wrong address mask %u.%u.%u.%u from "
9091da177e4SLinus Torvalds 					 "%s/%u.%u.%u.%u\n",
9101da177e4SLinus Torvalds 			       NIPQUAD(*mp), dev->name, NIPQUAD(rt->rt_src));
9111da177e4SLinus Torvalds 		}
9121da177e4SLinus Torvalds 	}
9131da177e4SLinus Torvalds 	rcu_read_unlock();
9141da177e4SLinus Torvalds 	in_dev_put(in_dev);
9151da177e4SLinus Torvalds out:;
9161da177e4SLinus Torvalds }
9171da177e4SLinus Torvalds 
9181da177e4SLinus Torvalds static void icmp_discard(struct sk_buff *skb)
9191da177e4SLinus Torvalds {
9201da177e4SLinus Torvalds }
9211da177e4SLinus Torvalds 
9221da177e4SLinus Torvalds /*
9231da177e4SLinus Torvalds  *	Deal with incoming ICMP packets.
9241da177e4SLinus Torvalds  */
9251da177e4SLinus Torvalds int icmp_rcv(struct sk_buff *skb)
9261da177e4SLinus Torvalds {
9271da177e4SLinus Torvalds 	struct icmphdr *icmph;
9281da177e4SLinus Torvalds 	struct rtable *rt = (struct rtable *)skb->dst;
9291da177e4SLinus Torvalds 
9301da177e4SLinus Torvalds 	ICMP_INC_STATS_BH(ICMP_MIB_INMSGS);
9311da177e4SLinus Torvalds 
9321da177e4SLinus Torvalds 	switch (skb->ip_summed) {
93384fa7933SPatrick McHardy 	case CHECKSUM_COMPLETE:
934d3bc23e7SAl Viro 		if (!csum_fold(skb->csum))
9351da177e4SLinus Torvalds 			break;
936fb286bb2SHerbert Xu 		/* fall through */
9371da177e4SLinus Torvalds 	case CHECKSUM_NONE:
938fb286bb2SHerbert Xu 		skb->csum = 0;
939fb286bb2SHerbert Xu 		if (__skb_checksum_complete(skb))
9401da177e4SLinus Torvalds 			goto error;
9411da177e4SLinus Torvalds 	}
9421da177e4SLinus Torvalds 
9431da177e4SLinus Torvalds 	if (!pskb_pull(skb, sizeof(struct icmphdr)))
9441da177e4SLinus Torvalds 		goto error;
9451da177e4SLinus Torvalds 
9461da177e4SLinus Torvalds 	icmph = skb->h.icmph;
9471da177e4SLinus Torvalds 
9481da177e4SLinus Torvalds 	/*
9491da177e4SLinus Torvalds 	 *	18 is the highest 'known' ICMP type. Anything else is a mystery
9501da177e4SLinus Torvalds 	 *
9511da177e4SLinus Torvalds 	 *	RFC 1122: 3.2.2  Unknown ICMP messages types MUST be silently
9521da177e4SLinus Torvalds 	 *		  discarded.
9531da177e4SLinus Torvalds 	 */
9541da177e4SLinus Torvalds 	if (icmph->type > NR_ICMP_TYPES)
9551da177e4SLinus Torvalds 		goto error;
9561da177e4SLinus Torvalds 
9571da177e4SLinus Torvalds 
9581da177e4SLinus Torvalds 	/*
9591da177e4SLinus Torvalds 	 *	Parse the ICMP message
9601da177e4SLinus Torvalds 	 */
9611da177e4SLinus Torvalds 
9621da177e4SLinus Torvalds  	if (rt->rt_flags & (RTCF_BROADCAST | RTCF_MULTICAST)) {
9631da177e4SLinus Torvalds 		/*
9641da177e4SLinus Torvalds 		 *	RFC 1122: 3.2.2.6 An ICMP_ECHO to broadcast MAY be
9651da177e4SLinus Torvalds 		 *	  silently ignored (we let user decide with a sysctl).
9661da177e4SLinus Torvalds 		 *	RFC 1122: 3.2.2.8 An ICMP_TIMESTAMP MAY be silently
9671da177e4SLinus Torvalds 		 *	  discarded if to broadcast/multicast.
9681da177e4SLinus Torvalds 		 */
9694c866aa7SAlexey Kuznetsov 		if ((icmph->type == ICMP_ECHO ||
9704c866aa7SAlexey Kuznetsov 		     icmph->type == ICMP_TIMESTAMP) &&
9711da177e4SLinus Torvalds 		    sysctl_icmp_echo_ignore_broadcasts) {
9721da177e4SLinus Torvalds 			goto error;
9731da177e4SLinus Torvalds 		}
9741da177e4SLinus Torvalds 		if (icmph->type != ICMP_ECHO &&
9751da177e4SLinus Torvalds 		    icmph->type != ICMP_TIMESTAMP &&
9761da177e4SLinus Torvalds 		    icmph->type != ICMP_ADDRESS &&
9771da177e4SLinus Torvalds 		    icmph->type != ICMP_ADDRESSREPLY) {
9781da177e4SLinus Torvalds 			goto error;
9791da177e4SLinus Torvalds   		}
9801da177e4SLinus Torvalds 	}
9811da177e4SLinus Torvalds 
9821da177e4SLinus Torvalds 	ICMP_INC_STATS_BH(icmp_pointers[icmph->type].input_entry);
9831da177e4SLinus Torvalds 	icmp_pointers[icmph->type].handler(skb);
9841da177e4SLinus Torvalds 
9851da177e4SLinus Torvalds drop:
9861da177e4SLinus Torvalds 	kfree_skb(skb);
9871da177e4SLinus Torvalds 	return 0;
9881da177e4SLinus Torvalds error:
9891da177e4SLinus Torvalds 	ICMP_INC_STATS_BH(ICMP_MIB_INERRORS);
9901da177e4SLinus Torvalds 	goto drop;
9911da177e4SLinus Torvalds }
9921da177e4SLinus Torvalds 
9931da177e4SLinus Torvalds /*
9941da177e4SLinus Torvalds  *	This table is the definition of how we handle ICMP.
9951da177e4SLinus Torvalds  */
9969b5b5cffSArjan van de Ven static const struct icmp_control icmp_pointers[NR_ICMP_TYPES + 1] = {
9971da177e4SLinus Torvalds 	[ICMP_ECHOREPLY] = {
9981da177e4SLinus Torvalds 		.output_entry = ICMP_MIB_OUTECHOREPS,
9991da177e4SLinus Torvalds 		.input_entry = ICMP_MIB_INECHOREPS,
10001da177e4SLinus Torvalds 		.handler = icmp_discard,
10011da177e4SLinus Torvalds 	},
10021da177e4SLinus Torvalds 	[1] = {
10031da177e4SLinus Torvalds 		.output_entry = ICMP_MIB_DUMMY,
10041da177e4SLinus Torvalds 		.input_entry = ICMP_MIB_INERRORS,
10051da177e4SLinus Torvalds 		.handler = icmp_discard,
10061da177e4SLinus Torvalds 		.error = 1,
10071da177e4SLinus Torvalds 	},
10081da177e4SLinus Torvalds 	[2] = {
10091da177e4SLinus Torvalds 		.output_entry = ICMP_MIB_DUMMY,
10101da177e4SLinus Torvalds 		.input_entry = ICMP_MIB_INERRORS,
10111da177e4SLinus Torvalds 		.handler = icmp_discard,
10121da177e4SLinus Torvalds 		.error = 1,
10131da177e4SLinus Torvalds 	},
10141da177e4SLinus Torvalds 	[ICMP_DEST_UNREACH] = {
10151da177e4SLinus Torvalds 		.output_entry = ICMP_MIB_OUTDESTUNREACHS,
10161da177e4SLinus Torvalds 		.input_entry = ICMP_MIB_INDESTUNREACHS,
10171da177e4SLinus Torvalds 		.handler = icmp_unreach,
10181da177e4SLinus Torvalds 		.error = 1,
10191da177e4SLinus Torvalds 	},
10201da177e4SLinus Torvalds 	[ICMP_SOURCE_QUENCH] = {
10211da177e4SLinus Torvalds 		.output_entry = ICMP_MIB_OUTSRCQUENCHS,
10221da177e4SLinus Torvalds 		.input_entry = ICMP_MIB_INSRCQUENCHS,
10231da177e4SLinus Torvalds 		.handler = icmp_unreach,
10241da177e4SLinus Torvalds 		.error = 1,
10251da177e4SLinus Torvalds 	},
10261da177e4SLinus Torvalds 	[ICMP_REDIRECT] = {
10271da177e4SLinus Torvalds 		.output_entry = ICMP_MIB_OUTREDIRECTS,
10281da177e4SLinus Torvalds 		.input_entry = ICMP_MIB_INREDIRECTS,
10291da177e4SLinus Torvalds 		.handler = icmp_redirect,
10301da177e4SLinus Torvalds 		.error = 1,
10311da177e4SLinus Torvalds 	},
10321da177e4SLinus Torvalds 	[6] = {
10331da177e4SLinus Torvalds 		.output_entry = ICMP_MIB_DUMMY,
10341da177e4SLinus Torvalds 		.input_entry = ICMP_MIB_INERRORS,
10351da177e4SLinus Torvalds 		.handler = icmp_discard,
10361da177e4SLinus Torvalds 		.error = 1,
10371da177e4SLinus Torvalds 	},
10381da177e4SLinus Torvalds 	[7] = {
10391da177e4SLinus Torvalds 		.output_entry = ICMP_MIB_DUMMY,
10401da177e4SLinus Torvalds 		.input_entry = ICMP_MIB_INERRORS,
10411da177e4SLinus Torvalds 		.handler = icmp_discard,
10421da177e4SLinus Torvalds 		.error = 1,
10431da177e4SLinus Torvalds 	},
10441da177e4SLinus Torvalds 	[ICMP_ECHO] = {
10451da177e4SLinus Torvalds 		.output_entry = ICMP_MIB_OUTECHOS,
10461da177e4SLinus Torvalds 		.input_entry = ICMP_MIB_INECHOS,
10471da177e4SLinus Torvalds 		.handler = icmp_echo,
10481da177e4SLinus Torvalds 	},
10491da177e4SLinus Torvalds 	[9] = {
10501da177e4SLinus Torvalds 		.output_entry = ICMP_MIB_DUMMY,
10511da177e4SLinus Torvalds 		.input_entry = ICMP_MIB_INERRORS,
10521da177e4SLinus Torvalds 		.handler = icmp_discard,
10531da177e4SLinus Torvalds 		.error = 1,
10541da177e4SLinus Torvalds 	},
10551da177e4SLinus Torvalds 	[10] = {
10561da177e4SLinus Torvalds 		.output_entry = ICMP_MIB_DUMMY,
10571da177e4SLinus Torvalds 		.input_entry = ICMP_MIB_INERRORS,
10581da177e4SLinus Torvalds 		.handler = icmp_discard,
10591da177e4SLinus Torvalds 		.error = 1,
10601da177e4SLinus Torvalds 	},
10611da177e4SLinus Torvalds 	[ICMP_TIME_EXCEEDED] = {
10621da177e4SLinus Torvalds 		.output_entry = ICMP_MIB_OUTTIMEEXCDS,
10631da177e4SLinus Torvalds 		.input_entry = ICMP_MIB_INTIMEEXCDS,
10641da177e4SLinus Torvalds 		.handler = icmp_unreach,
10651da177e4SLinus Torvalds 		.error = 1,
10661da177e4SLinus Torvalds 	},
10671da177e4SLinus Torvalds 	[ICMP_PARAMETERPROB] = {
10681da177e4SLinus Torvalds 		.output_entry = ICMP_MIB_OUTPARMPROBS,
10691da177e4SLinus Torvalds 		.input_entry = ICMP_MIB_INPARMPROBS,
10701da177e4SLinus Torvalds 		.handler = icmp_unreach,
10711da177e4SLinus Torvalds 		.error = 1,
10721da177e4SLinus Torvalds 	},
10731da177e4SLinus Torvalds 	[ICMP_TIMESTAMP] = {
10741da177e4SLinus Torvalds 		.output_entry = ICMP_MIB_OUTTIMESTAMPS,
10751da177e4SLinus Torvalds 		.input_entry = ICMP_MIB_INTIMESTAMPS,
10761da177e4SLinus Torvalds 		.handler = icmp_timestamp,
10771da177e4SLinus Torvalds 	},
10781da177e4SLinus Torvalds 	[ICMP_TIMESTAMPREPLY] = {
10791da177e4SLinus Torvalds 		.output_entry = ICMP_MIB_OUTTIMESTAMPREPS,
10801da177e4SLinus Torvalds 		.input_entry = ICMP_MIB_INTIMESTAMPREPS,
10811da177e4SLinus Torvalds 		.handler = icmp_discard,
10821da177e4SLinus Torvalds 	},
10831da177e4SLinus Torvalds 	[ICMP_INFO_REQUEST] = {
10841da177e4SLinus Torvalds 		.output_entry = ICMP_MIB_DUMMY,
10851da177e4SLinus Torvalds 		.input_entry = ICMP_MIB_DUMMY,
10861da177e4SLinus Torvalds 		.handler = icmp_discard,
10871da177e4SLinus Torvalds 	},
10881da177e4SLinus Torvalds  	[ICMP_INFO_REPLY] = {
10891da177e4SLinus Torvalds 		.output_entry = ICMP_MIB_DUMMY,
10901da177e4SLinus Torvalds 		.input_entry = ICMP_MIB_DUMMY,
10911da177e4SLinus Torvalds 		.handler = icmp_discard,
10921da177e4SLinus Torvalds 	},
10931da177e4SLinus Torvalds 	[ICMP_ADDRESS] = {
10941da177e4SLinus Torvalds 		.output_entry = ICMP_MIB_OUTADDRMASKS,
10951da177e4SLinus Torvalds 		.input_entry = ICMP_MIB_INADDRMASKS,
10961da177e4SLinus Torvalds 		.handler = icmp_address,
10971da177e4SLinus Torvalds 	},
10981da177e4SLinus Torvalds 	[ICMP_ADDRESSREPLY] = {
10991da177e4SLinus Torvalds 		.output_entry = ICMP_MIB_OUTADDRMASKREPS,
11001da177e4SLinus Torvalds 		.input_entry = ICMP_MIB_INADDRMASKREPS,
11011da177e4SLinus Torvalds 		.handler = icmp_address_reply,
11021da177e4SLinus Torvalds 	},
11031da177e4SLinus Torvalds };
11041da177e4SLinus Torvalds 
11051da177e4SLinus Torvalds void __init icmp_init(struct net_proto_family *ops)
11061da177e4SLinus Torvalds {
11071da177e4SLinus Torvalds 	struct inet_sock *inet;
11081da177e4SLinus Torvalds 	int i;
11091da177e4SLinus Torvalds 
11106f912042SKAMEZAWA Hiroyuki 	for_each_possible_cpu(i) {
11111da177e4SLinus Torvalds 		int err;
11121da177e4SLinus Torvalds 
11131da177e4SLinus Torvalds 		err = sock_create_kern(PF_INET, SOCK_RAW, IPPROTO_ICMP,
11141da177e4SLinus Torvalds 				       &per_cpu(__icmp_socket, i));
11151da177e4SLinus Torvalds 
11161da177e4SLinus Torvalds 		if (err < 0)
11171da177e4SLinus Torvalds 			panic("Failed to create the ICMP control socket.\n");
11181da177e4SLinus Torvalds 
11191da177e4SLinus Torvalds 		per_cpu(__icmp_socket, i)->sk->sk_allocation = GFP_ATOMIC;
11201da177e4SLinus Torvalds 
11211da177e4SLinus Torvalds 		/* Enough space for 2 64K ICMP packets, including
11221da177e4SLinus Torvalds 		 * sk_buff struct overhead.
11231da177e4SLinus Torvalds 		 */
11241da177e4SLinus Torvalds 		per_cpu(__icmp_socket, i)->sk->sk_sndbuf =
11251da177e4SLinus Torvalds 			(2 * ((64 * 1024) + sizeof(struct sk_buff)));
11261da177e4SLinus Torvalds 
11271da177e4SLinus Torvalds 		inet = inet_sk(per_cpu(__icmp_socket, i)->sk);
11281da177e4SLinus Torvalds 		inet->uc_ttl = -1;
11291da177e4SLinus Torvalds 		inet->pmtudisc = IP_PMTUDISC_DONT;
11301da177e4SLinus Torvalds 
11311da177e4SLinus Torvalds 		/* Unhash it so that IP input processing does not even
11321da177e4SLinus Torvalds 		 * see it, we do not wish this socket to see incoming
11331da177e4SLinus Torvalds 		 * packets.
11341da177e4SLinus Torvalds 		 */
11351da177e4SLinus Torvalds 		per_cpu(__icmp_socket, i)->sk->sk_prot->unhash(per_cpu(__icmp_socket, i)->sk);
11361da177e4SLinus Torvalds 	}
11371da177e4SLinus Torvalds }
11381da177e4SLinus Torvalds 
11391da177e4SLinus Torvalds EXPORT_SYMBOL(icmp_err_convert);
11401da177e4SLinus Torvalds EXPORT_SYMBOL(icmp_send);
11411da177e4SLinus Torvalds EXPORT_SYMBOL(icmp_statistics);
11421da177e4SLinus Torvalds EXPORT_SYMBOL(xrlim_allow);
1143