xref: /freebsd/sys/netinet/ip_icmp.c (revision b9234fafa0783687e83b2fa646e3ee137d87913a)
1df8bae1dSRodney W. Grimes /*
2df8bae1dSRodney W. Grimes  * Copyright (c) 1982, 1986, 1988, 1993
3df8bae1dSRodney W. Grimes  *	The Regents of the University of California.  All rights reserved.
4df8bae1dSRodney W. Grimes  *
5df8bae1dSRodney W. Grimes  * Redistribution and use in source and binary forms, with or without
6df8bae1dSRodney W. Grimes  * modification, are permitted provided that the following conditions
7df8bae1dSRodney W. Grimes  * are met:
8df8bae1dSRodney W. Grimes  * 1. Redistributions of source code must retain the above copyright
9df8bae1dSRodney W. Grimes  *    notice, this list of conditions and the following disclaimer.
10df8bae1dSRodney W. Grimes  * 2. Redistributions in binary form must reproduce the above copyright
11df8bae1dSRodney W. Grimes  *    notice, this list of conditions and the following disclaimer in the
12df8bae1dSRodney W. Grimes  *    documentation and/or other materials provided with the distribution.
13df8bae1dSRodney W. Grimes  * 3. All advertising materials mentioning features or use of this software
14df8bae1dSRodney W. Grimes  *    must display the following acknowledgement:
15df8bae1dSRodney W. Grimes  *	This product includes software developed by the University of
16df8bae1dSRodney W. Grimes  *	California, Berkeley and its contributors.
17df8bae1dSRodney W. Grimes  * 4. Neither the name of the University nor the names of its contributors
18df8bae1dSRodney W. Grimes  *    may be used to endorse or promote products derived from this software
19df8bae1dSRodney W. Grimes  *    without specific prior written permission.
20df8bae1dSRodney W. Grimes  *
21df8bae1dSRodney W. Grimes  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22df8bae1dSRodney W. Grimes  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23df8bae1dSRodney W. Grimes  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24df8bae1dSRodney W. Grimes  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25df8bae1dSRodney W. Grimes  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26df8bae1dSRodney W. Grimes  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27df8bae1dSRodney W. Grimes  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28df8bae1dSRodney W. Grimes  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29df8bae1dSRodney W. Grimes  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30df8bae1dSRodney W. Grimes  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31df8bae1dSRodney W. Grimes  * SUCH DAMAGE.
32df8bae1dSRodney W. Grimes  *
33df8bae1dSRodney W. Grimes  *	@(#)ip_icmp.c	8.2 (Berkeley) 1/4/94
34c3aac50fSPeter Wemm  * $FreeBSD$
35df8bae1dSRodney W. Grimes  */
36df8bae1dSRodney W. Grimes 
376a800098SYoshinobu Inoue #include "opt_ipsec.h"
380070e096SRobert Watson #include "opt_mac.h"
396a800098SYoshinobu Inoue 
40df8bae1dSRodney W. Grimes #include <sys/param.h>
41df8bae1dSRodney W. Grimes #include <sys/systm.h>
420070e096SRobert Watson #include <sys/mac.h>
43df8bae1dSRodney W. Grimes #include <sys/mbuf.h>
44df8bae1dSRodney W. Grimes #include <sys/protosw.h>
45df8bae1dSRodney W. Grimes #include <sys/socket.h>
46df8bae1dSRodney W. Grimes #include <sys/time.h>
47df8bae1dSRodney W. Grimes #include <sys/kernel.h>
48b5e8ce9fSBruce Evans #include <sys/sysctl.h>
49df8bae1dSRodney W. Grimes 
50df8bae1dSRodney W. Grimes #include <net/if.h>
519494d596SBrooks Davis #include <net/if_types.h>
52df8bae1dSRodney W. Grimes #include <net/route.h>
53df8bae1dSRodney W. Grimes 
545e2d0696SGarrett Wollman #define _IP_VHL
55df8bae1dSRodney W. Grimes #include <netinet/in.h>
56df8bae1dSRodney W. Grimes #include <netinet/in_systm.h>
57df8bae1dSRodney W. Grimes #include <netinet/in_var.h>
58df8bae1dSRodney W. Grimes #include <netinet/ip.h>
59df8bae1dSRodney W. Grimes #include <netinet/ip_icmp.h>
60b5e8ce9fSBruce Evans #include <netinet/ip_var.h>
61df8bae1dSRodney W. Grimes #include <netinet/icmp_var.h>
62df8bae1dSRodney W. Grimes 
636a800098SYoshinobu Inoue #ifdef IPSEC
646a800098SYoshinobu Inoue #include <netinet6/ipsec.h>
656a800098SYoshinobu Inoue #include <netkey/key.h>
666a800098SYoshinobu Inoue #endif
676a800098SYoshinobu Inoue 
68b9234fafSSam Leffler #ifdef FAST_IPSEC
69b9234fafSSam Leffler #include <netipsec/ipsec.h>
70b9234fafSSam Leffler #include <netipsec/key.h>
71b9234fafSSam Leffler #define	IPSEC
72b9234fafSSam Leffler #endif
73b9234fafSSam Leffler 
7472a52a35SJonathan Lemon #include <machine/in_cksum.h>
7572a52a35SJonathan Lemon 
76df8bae1dSRodney W. Grimes /*
77df8bae1dSRodney W. Grimes  * ICMP routines: error generation, receive packet processing, and
78df8bae1dSRodney W. Grimes  * routines to turnaround packets back to the originator, and
79df8bae1dSRodney W. Grimes  * host table maintenance routines.
80df8bae1dSRodney W. Grimes  */
81df8bae1dSRodney W. Grimes 
82f708ef1bSPoul-Henning Kamp static struct	icmpstat icmpstat;
83c73d99b5SRuslan Ermilov SYSCTL_STRUCT(_net_inet_icmp, ICMPCTL_STATS, stats, CTLFLAG_RW,
840312fbe9SPoul-Henning Kamp 	&icmpstat, icmpstat, "");
850312fbe9SPoul-Henning Kamp 
860312fbe9SPoul-Henning Kamp static int	icmpmaskrepl = 0;
870312fbe9SPoul-Henning Kamp SYSCTL_INT(_net_inet_icmp, ICMPCTL_MASKREPL, maskrepl, CTLFLAG_RW,
880312fbe9SPoul-Henning Kamp 	&icmpmaskrepl, 0, "");
890312fbe9SPoul-Henning Kamp 
9018d3153eSDag-Erling Smørgrav static int	drop_redirect = 0;
9118d3153eSDag-Erling Smørgrav SYSCTL_INT(_net_inet_icmp, OID_AUTO, drop_redirect, CTLFLAG_RW,
9218d3153eSDag-Erling Smørgrav 	&drop_redirect, 0, "");
9318d3153eSDag-Erling Smørgrav 
946c3b5f69SDag-Erling Smørgrav static int	log_redirect = 0;
956c3b5f69SDag-Erling Smørgrav SYSCTL_INT(_net_inet_icmp, OID_AUTO, log_redirect, CTLFLAG_RW,
966c3b5f69SDag-Erling Smørgrav 	&log_redirect, 0, "");
976c3b5f69SDag-Erling Smørgrav 
98173c0f9fSWarner Losh static int      icmplim = 200;
9951508de1SMatthew Dillon SYSCTL_INT(_net_inet_icmp, ICMPCTL_ICMPLIM, icmplim, CTLFLAG_RW,
10051508de1SMatthew Dillon 	&icmplim, 0, "");
1015fce7fc4SMatthew Dillon 
1024f14ee00SDan Moschuk static int	icmplim_output = 1;
1034f14ee00SDan Moschuk SYSCTL_INT(_net_inet_icmp, OID_AUTO, icmplim_output, CTLFLAG_RW,
1044f14ee00SDan Moschuk 	&icmplim_output, 0, "");
10551508de1SMatthew Dillon 
1065fce7fc4SMatthew Dillon /*
1075fce7fc4SMatthew Dillon  * ICMP broadcast echo sysctl
1085fce7fc4SMatthew Dillon  */
1095fce7fc4SMatthew Dillon 
11061a4defdSJoseph Koshy static int	icmpbmcastecho = 0;
11118d3153eSDag-Erling Smørgrav SYSCTL_INT(_net_inet_icmp, OID_AUTO, bmcastecho, CTLFLAG_RW,
11218d3153eSDag-Erling Smørgrav 	&icmpbmcastecho, 0, "");
1137022ea0aSGarrett Wollman 
11451508de1SMatthew Dillon 
115df8bae1dSRodney W. Grimes #ifdef ICMPPRINTFS
116df8bae1dSRodney W. Grimes int	icmpprintfs = 0;
117df8bae1dSRodney W. Grimes #endif
118df8bae1dSRodney W. Grimes 
1194d77a549SAlfred Perlstein static void	icmp_reflect(struct mbuf *);
1204d77a549SAlfred Perlstein static void	icmp_send(struct mbuf *, struct mbuf *, struct route *);
1214d77a549SAlfred Perlstein static int	ip_next_mtu(int, int);
1220312fbe9SPoul-Henning Kamp 
123df8bae1dSRodney W. Grimes extern	struct protosw inetsw[];
124df8bae1dSRodney W. Grimes 
125df8bae1dSRodney W. Grimes /*
126df8bae1dSRodney W. Grimes  * Generate an error packet of type error
127df8bae1dSRodney W. Grimes  * in response to bad packet ip.
128df8bae1dSRodney W. Grimes  */
129df8bae1dSRodney W. Grimes void
130df8bae1dSRodney W. Grimes icmp_error(n, type, code, dest, destifp)
131df8bae1dSRodney W. Grimes 	struct mbuf *n;
132df8bae1dSRodney W. Grimes 	int type, code;
133df8bae1dSRodney W. Grimes 	n_long dest;
134df8bae1dSRodney W. Grimes 	struct ifnet *destifp;
135df8bae1dSRodney W. Grimes {
136df8bae1dSRodney W. Grimes 	register struct ip *oip = mtod(n, struct ip *), *nip;
1375e2d0696SGarrett Wollman 	register unsigned oiplen = IP_VHL_HL(oip->ip_vhl) << 2;
138df8bae1dSRodney W. Grimes 	register struct icmp *icp;
139df8bae1dSRodney W. Grimes 	register struct mbuf *m;
140df8bae1dSRodney W. Grimes 	unsigned icmplen;
141df8bae1dSRodney W. Grimes 
142df8bae1dSRodney W. Grimes #ifdef ICMPPRINTFS
143df8bae1dSRodney W. Grimes 	if (icmpprintfs)
144623ae52eSPoul-Henning Kamp 		printf("icmp_error(%p, %x, %d)\n", oip, type, code);
145df8bae1dSRodney W. Grimes #endif
146df8bae1dSRodney W. Grimes 	if (type != ICMP_REDIRECT)
147df8bae1dSRodney W. Grimes 		icmpstat.icps_error++;
148df8bae1dSRodney W. Grimes 	/*
149df8bae1dSRodney W. Grimes 	 * Don't send error if not the first fragment of message.
150df8bae1dSRodney W. Grimes 	 * Don't error if the old packet protocol was ICMP
151df8bae1dSRodney W. Grimes 	 * error message, only known informational types.
152df8bae1dSRodney W. Grimes 	 */
153df8bae1dSRodney W. Grimes 	if (oip->ip_off &~ (IP_MF|IP_DF))
154df8bae1dSRodney W. Grimes 		goto freeit;
155df8bae1dSRodney W. Grimes 	if (oip->ip_p == IPPROTO_ICMP && type != ICMP_REDIRECT &&
156df8bae1dSRodney W. Grimes 	  n->m_len >= oiplen + ICMP_MINLEN &&
157df8bae1dSRodney W. Grimes 	  !ICMP_INFOTYPE(((struct icmp *)((caddr_t)oip + oiplen))->icmp_type)) {
158df8bae1dSRodney W. Grimes 		icmpstat.icps_oldicmp++;
159df8bae1dSRodney W. Grimes 		goto freeit;
160df8bae1dSRodney W. Grimes 	}
161df8bae1dSRodney W. Grimes 	/* Don't send error in response to a multicast or broadcast packet */
162df8bae1dSRodney W. Grimes 	if (n->m_flags & (M_BCAST|M_MCAST))
163df8bae1dSRodney W. Grimes 		goto freeit;
164df8bae1dSRodney W. Grimes 	/*
165df8bae1dSRodney W. Grimes 	 * First, formulate icmp message
166df8bae1dSRodney W. Grimes 	 */
167df8bae1dSRodney W. Grimes 	m = m_gethdr(M_DONTWAIT, MT_HEADER);
168df8bae1dSRodney W. Grimes 	if (m == NULL)
169df8bae1dSRodney W. Grimes 		goto freeit;
1700070e096SRobert Watson #ifdef MAC
1710070e096SRobert Watson 	mac_create_mbuf_netlayer(n, m);
1720070e096SRobert Watson #endif
1731d027522SRuslan Ermilov 	icmplen = min(oiplen + 8, oip->ip_len);
174bfef7ed4SIan Dowse 	if (icmplen < sizeof(struct ip))
175bfef7ed4SIan Dowse 		panic("icmp_error: bad length");
176df8bae1dSRodney W. Grimes 	m->m_len = icmplen + ICMP_MINLEN;
177df8bae1dSRodney W. Grimes 	MH_ALIGN(m, m->m_len);
178df8bae1dSRodney W. Grimes 	icp = mtod(m, struct icmp *);
179df8bae1dSRodney W. Grimes 	if ((u_int)type > ICMP_MAXTYPE)
180df8bae1dSRodney W. Grimes 		panic("icmp_error");
181df8bae1dSRodney W. Grimes 	icmpstat.icps_outhist[type]++;
182df8bae1dSRodney W. Grimes 	icp->icmp_type = type;
183df8bae1dSRodney W. Grimes 	if (type == ICMP_REDIRECT)
184df8bae1dSRodney W. Grimes 		icp->icmp_gwaddr.s_addr = dest;
185df8bae1dSRodney W. Grimes 	else {
186df8bae1dSRodney W. Grimes 		icp->icmp_void = 0;
187df8bae1dSRodney W. Grimes 		/*
188df8bae1dSRodney W. Grimes 		 * The following assignments assume an overlay with the
189df8bae1dSRodney W. Grimes 		 * zeroed icmp_void field.
190df8bae1dSRodney W. Grimes 		 */
191df8bae1dSRodney W. Grimes 		if (type == ICMP_PARAMPROB) {
192df8bae1dSRodney W. Grimes 			icp->icmp_pptr = code;
193df8bae1dSRodney W. Grimes 			code = 0;
194df8bae1dSRodney W. Grimes 		} else if (type == ICMP_UNREACH &&
195df8bae1dSRodney W. Grimes 			code == ICMP_UNREACH_NEEDFRAG && destifp) {
196df8bae1dSRodney W. Grimes 			icp->icmp_nextmtu = htons(destifp->if_mtu);
197df8bae1dSRodney W. Grimes 		}
198df8bae1dSRodney W. Grimes 	}
199df8bae1dSRodney W. Grimes 
200df8bae1dSRodney W. Grimes 	icp->icmp_code = code;
201bfef7ed4SIan Dowse 	m_copydata(n, 0, icmplen, (caddr_t)&icp->icmp_ip);
202df8bae1dSRodney W. Grimes 	nip = &icp->icmp_ip;
20304287599SRuslan Ermilov 
20404287599SRuslan Ermilov 	/*
20504287599SRuslan Ermilov 	 * Convert fields to network representation.
20604287599SRuslan Ermilov 	 */
207fd8e4ebcSMike Barcroft 	nip->ip_len = htons(nip->ip_len);
208fd8e4ebcSMike Barcroft 	nip->ip_off = htons(nip->ip_off);
209df8bae1dSRodney W. Grimes 
210df8bae1dSRodney W. Grimes 	/*
211df8bae1dSRodney W. Grimes 	 * Now, copy old ip header (without options)
212df8bae1dSRodney W. Grimes 	 * in front of icmp message.
213df8bae1dSRodney W. Grimes 	 */
214df8bae1dSRodney W. Grimes 	if (m->m_data - sizeof(struct ip) < m->m_pktdat)
215df8bae1dSRodney W. Grimes 		panic("icmp len");
216df8bae1dSRodney W. Grimes 	m->m_data -= sizeof(struct ip);
217df8bae1dSRodney W. Grimes 	m->m_len += sizeof(struct ip);
218df8bae1dSRodney W. Grimes 	m->m_pkthdr.len = m->m_len;
219df8bae1dSRodney W. Grimes 	m->m_pkthdr.rcvif = n->m_pkthdr.rcvif;
220df8bae1dSRodney W. Grimes 	nip = mtod(m, struct ip *);
221df8bae1dSRodney W. Grimes 	bcopy((caddr_t)oip, (caddr_t)nip, sizeof(struct ip));
222df8bae1dSRodney W. Grimes 	nip->ip_len = m->m_len;
2235e2d0696SGarrett Wollman 	nip->ip_vhl = IP_VHL_BORING;
224df8bae1dSRodney W. Grimes 	nip->ip_p = IPPROTO_ICMP;
225df8bae1dSRodney W. Grimes 	nip->ip_tos = 0;
226df8bae1dSRodney W. Grimes 	icmp_reflect(m);
227df8bae1dSRodney W. Grimes 
228df8bae1dSRodney W. Grimes freeit:
229df8bae1dSRodney W. Grimes 	m_freem(n);
230df8bae1dSRodney W. Grimes }
231df8bae1dSRodney W. Grimes 
232df8bae1dSRodney W. Grimes static struct sockaddr_in icmpsrc = { sizeof (struct sockaddr_in), AF_INET };
233df8bae1dSRodney W. Grimes static struct sockaddr_in icmpdst = { sizeof (struct sockaddr_in), AF_INET };
234df8bae1dSRodney W. Grimes static struct sockaddr_in icmpgw = { sizeof (struct sockaddr_in), AF_INET };
235df8bae1dSRodney W. Grimes 
236df8bae1dSRodney W. Grimes /*
237df8bae1dSRodney W. Grimes  * Process a received ICMP message.
238df8bae1dSRodney W. Grimes  */
239df8bae1dSRodney W. Grimes void
240f0ffb944SJulian Elischer icmp_input(m, off)
241df8bae1dSRodney W. Grimes 	register struct mbuf *m;
242f0ffb944SJulian Elischer 	int off;
243df8bae1dSRodney W. Grimes {
2446a800098SYoshinobu Inoue 	int hlen = off;
245df8bae1dSRodney W. Grimes 	register struct icmp *icp;
246df8bae1dSRodney W. Grimes 	register struct ip *ip = mtod(m, struct ip *);
247df8bae1dSRodney W. Grimes 	int icmplen = ip->ip_len;
248df8bae1dSRodney W. Grimes 	register int i;
249df8bae1dSRodney W. Grimes 	struct in_ifaddr *ia;
2504d77a549SAlfred Perlstein 	void (*ctlfunc)(int, struct sockaddr *, void *);
251df8bae1dSRodney W. Grimes 	int code;
252df8bae1dSRodney W. Grimes 
253df8bae1dSRodney W. Grimes 	/*
254df8bae1dSRodney W. Grimes 	 * Locate icmp structure in mbuf, and check
255df8bae1dSRodney W. Grimes 	 * that not corrupted and of at least minimum length.
256df8bae1dSRodney W. Grimes 	 */
257df8bae1dSRodney W. Grimes #ifdef ICMPPRINTFS
2582b758395SGarrett Wollman 	if (icmpprintfs) {
2592b758395SGarrett Wollman 		char buf[4 * sizeof "123"];
2602b758395SGarrett Wollman 		strcpy(buf, inet_ntoa(ip->ip_src));
2612b758395SGarrett Wollman 		printf("icmp_input from %s to %s, len %d\n",
2622b758395SGarrett Wollman 		       buf, inet_ntoa(ip->ip_dst), icmplen);
2632b758395SGarrett Wollman 	}
264df8bae1dSRodney W. Grimes #endif
265df8bae1dSRodney W. Grimes 	if (icmplen < ICMP_MINLEN) {
266df8bae1dSRodney W. Grimes 		icmpstat.icps_tooshort++;
267df8bae1dSRodney W. Grimes 		goto freeit;
268df8bae1dSRodney W. Grimes 	}
269df8bae1dSRodney W. Grimes 	i = hlen + min(icmplen, ICMP_ADVLENMIN);
270df8bae1dSRodney W. Grimes 	if (m->m_len < i && (m = m_pullup(m, i)) == 0)  {
271df8bae1dSRodney W. Grimes 		icmpstat.icps_tooshort++;
272df8bae1dSRodney W. Grimes 		return;
273df8bae1dSRodney W. Grimes 	}
274df8bae1dSRodney W. Grimes 	ip = mtod(m, struct ip *);
275df8bae1dSRodney W. Grimes 	m->m_len -= hlen;
276df8bae1dSRodney W. Grimes 	m->m_data += hlen;
277df8bae1dSRodney W. Grimes 	icp = mtod(m, struct icmp *);
278df8bae1dSRodney W. Grimes 	if (in_cksum(m, icmplen)) {
279df8bae1dSRodney W. Grimes 		icmpstat.icps_checksum++;
280df8bae1dSRodney W. Grimes 		goto freeit;
281df8bae1dSRodney W. Grimes 	}
282df8bae1dSRodney W. Grimes 	m->m_len += hlen;
283df8bae1dSRodney W. Grimes 	m->m_data -= hlen;
284df8bae1dSRodney W. Grimes 
2856a800098SYoshinobu Inoue 	if (m->m_pkthdr.rcvif && m->m_pkthdr.rcvif->if_type == IFT_FAITH) {
2866a800098SYoshinobu Inoue 		/*
2876a800098SYoshinobu Inoue 		 * Deliver very specific ICMP type only.
2886a800098SYoshinobu Inoue 		 */
2896a800098SYoshinobu Inoue 		switch (icp->icmp_type) {
2906a800098SYoshinobu Inoue 		case ICMP_UNREACH:
2916a800098SYoshinobu Inoue 		case ICMP_TIMXCEED:
2926a800098SYoshinobu Inoue 			break;
2936a800098SYoshinobu Inoue 		default:
2946a800098SYoshinobu Inoue 			goto freeit;
2956a800098SYoshinobu Inoue 		}
2966a800098SYoshinobu Inoue 	}
2976a800098SYoshinobu Inoue 
298df8bae1dSRodney W. Grimes #ifdef ICMPPRINTFS
299df8bae1dSRodney W. Grimes 	if (icmpprintfs)
300df8bae1dSRodney W. Grimes 		printf("icmp_input, type %d code %d\n", icp->icmp_type,
301df8bae1dSRodney W. Grimes 		    icp->icmp_code);
302df8bae1dSRodney W. Grimes #endif
3035b7ee6edSGarrett Wollman 
3045b7ee6edSGarrett Wollman 	/*
3055b7ee6edSGarrett Wollman 	 * Message type specific processing.
3065b7ee6edSGarrett Wollman 	 */
307df8bae1dSRodney W. Grimes 	if (icp->icmp_type > ICMP_MAXTYPE)
308df8bae1dSRodney W. Grimes 		goto raw;
309df8bae1dSRodney W. Grimes 	icmpstat.icps_inhist[icp->icmp_type]++;
310df8bae1dSRodney W. Grimes 	code = icp->icmp_code;
311df8bae1dSRodney W. Grimes 	switch (icp->icmp_type) {
312df8bae1dSRodney W. Grimes 
313df8bae1dSRodney W. Grimes 	case ICMP_UNREACH:
314df8bae1dSRodney W. Grimes 		switch (code) {
315df8bae1dSRodney W. Grimes 			case ICMP_UNREACH_NET:
316df8bae1dSRodney W. Grimes 			case ICMP_UNREACH_HOST:
317df8bae1dSRodney W. Grimes 			case ICMP_UNREACH_SRCFAIL:
318e4bb5b05SJonathan Lemon 			case ICMP_UNREACH_NET_UNKNOWN:
319e4bb5b05SJonathan Lemon 			case ICMP_UNREACH_HOST_UNKNOWN:
320e4bb5b05SJonathan Lemon 			case ICMP_UNREACH_ISOLATED:
321e4bb5b05SJonathan Lemon 			case ICMP_UNREACH_TOSNET:
322e4bb5b05SJonathan Lemon 			case ICMP_UNREACH_TOSHOST:
323e4bb5b05SJonathan Lemon 			case ICMP_UNREACH_HOST_PRECEDENCE:
324e4bb5b05SJonathan Lemon 			case ICMP_UNREACH_PRECEDENCE_CUTOFF:
325e4bb5b05SJonathan Lemon 				code = PRC_UNREACH_NET;
326df8bae1dSRodney W. Grimes 				break;
327df8bae1dSRodney W. Grimes 
328df8bae1dSRodney W. Grimes 			case ICMP_UNREACH_NEEDFRAG:
329df8bae1dSRodney W. Grimes 				code = PRC_MSGSIZE;
330df8bae1dSRodney W. Grimes 				break;
331df8bae1dSRodney W. Grimes 
332e4bb5b05SJonathan Lemon 			/*
333e4bb5b05SJonathan Lemon 			 * RFC 1122, Sections 3.2.2.1 and 4.2.3.9.
334e4bb5b05SJonathan Lemon 			 * Treat subcodes 2,3 as immediate RST
335e4bb5b05SJonathan Lemon 			 */
336e4bb5b05SJonathan Lemon 			case ICMP_UNREACH_PROTOCOL:
337e4bb5b05SJonathan Lemon 			case ICMP_UNREACH_PORT:
338b77d155dSJesper Skriver 				code = PRC_UNREACH_PORT;
339b11d7a4aSPoul-Henning Kamp 				break;
34090fcbbd6SPoul-Henning Kamp 
34190fcbbd6SPoul-Henning Kamp 			case ICMP_UNREACH_NET_PROHIB:
34290fcbbd6SPoul-Henning Kamp 			case ICMP_UNREACH_HOST_PROHIB:
3439c4b2574SPaul Traina 			case ICMP_UNREACH_FILTER_PROHIB:
34490fcbbd6SPoul-Henning Kamp 				code = PRC_UNREACH_ADMIN_PROHIB;
345b11d7a4aSPoul-Henning Kamp 				break;
346b11d7a4aSPoul-Henning Kamp 
347df8bae1dSRodney W. Grimes 			default:
348df8bae1dSRodney W. Grimes 				goto badcode;
349df8bae1dSRodney W. Grimes 		}
350df8bae1dSRodney W. Grimes 		goto deliver;
351df8bae1dSRodney W. Grimes 
352df8bae1dSRodney W. Grimes 	case ICMP_TIMXCEED:
353df8bae1dSRodney W. Grimes 		if (code > 1)
354df8bae1dSRodney W. Grimes 			goto badcode;
355df8bae1dSRodney W. Grimes 		code += PRC_TIMXCEED_INTRANS;
356df8bae1dSRodney W. Grimes 		goto deliver;
357df8bae1dSRodney W. Grimes 
358df8bae1dSRodney W. Grimes 	case ICMP_PARAMPROB:
359df8bae1dSRodney W. Grimes 		if (code > 1)
360df8bae1dSRodney W. Grimes 			goto badcode;
361df8bae1dSRodney W. Grimes 		code = PRC_PARAMPROB;
362df8bae1dSRodney W. Grimes 		goto deliver;
363df8bae1dSRodney W. Grimes 
364df8bae1dSRodney W. Grimes 	case ICMP_SOURCEQUENCH:
365df8bae1dSRodney W. Grimes 		if (code)
366df8bae1dSRodney W. Grimes 			goto badcode;
367df8bae1dSRodney W. Grimes 		code = PRC_QUENCH;
368df8bae1dSRodney W. Grimes 	deliver:
369df8bae1dSRodney W. Grimes 		/*
370df8bae1dSRodney W. Grimes 		 * Problem with datagram; advise higher level routines.
371df8bae1dSRodney W. Grimes 		 */
372df8bae1dSRodney W. Grimes 		if (icmplen < ICMP_ADVLENMIN || icmplen < ICMP_ADVLEN(icp) ||
3735e2d0696SGarrett Wollman 		    IP_VHL_HL(icp->icmp_ip.ip_vhl) < (sizeof(struct ip) >> 2)) {
374df8bae1dSRodney W. Grimes 			icmpstat.icps_badlen++;
375df8bae1dSRodney W. Grimes 			goto freeit;
376df8bae1dSRodney W. Grimes 		}
377fd8e4ebcSMike Barcroft 		icp->icmp_ip.ip_len = ntohs(icp->icmp_ip.ip_len);
3785b7ee6edSGarrett Wollman 		/* Discard ICMP's in response to multicast packets */
3795b7ee6edSGarrett Wollman 		if (IN_MULTICAST(ntohl(icp->icmp_ip.ip_dst.s_addr)))
3805b7ee6edSGarrett Wollman 			goto badcode;
381df8bae1dSRodney W. Grimes #ifdef ICMPPRINTFS
382df8bae1dSRodney W. Grimes 		if (icmpprintfs)
383df8bae1dSRodney W. Grimes 			printf("deliver to protocol %d\n", icp->icmp_ip.ip_p);
384df8bae1dSRodney W. Grimes #endif
385df8bae1dSRodney W. Grimes 		icmpsrc.sin_addr = icp->icmp_ip.ip_dst;
386b7a44e34SGarrett Wollman #if 1
3875cbf3e08SGarrett Wollman 		/*
3885cbf3e08SGarrett Wollman 		 * MTU discovery:
3895cbf3e08SGarrett Wollman 		 * If we got a needfrag and there is a host route to the
3905cbf3e08SGarrett Wollman 		 * original destination, and the MTU is not locked, then
3915cbf3e08SGarrett Wollman 		 * set the MTU in the route to the suggested new value
3925cbf3e08SGarrett Wollman 		 * (if given) and then notify as usual.  The ULPs will
3935cbf3e08SGarrett Wollman 		 * notice that the MTU has changed and adapt accordingly.
3945cbf3e08SGarrett Wollman 		 * If no new MTU was suggested, then we guess a new one
3955cbf3e08SGarrett Wollman 		 * less than the current value.  If the new MTU is
3965cbf3e08SGarrett Wollman 		 * unreasonably small (arbitrarily set at 296), then
3975cbf3e08SGarrett Wollman 		 * we reset the MTU to the interface value and enable the
3985cbf3e08SGarrett Wollman 		 * lock bit, indicating that we are no longer doing MTU
3995cbf3e08SGarrett Wollman 		 * discovery.
4005cbf3e08SGarrett Wollman 		 */
4015cbf3e08SGarrett Wollman 		if (code == PRC_MSGSIZE) {
4025cbf3e08SGarrett Wollman 			struct rtentry *rt;
4035cbf3e08SGarrett Wollman 			int mtu;
4045cbf3e08SGarrett Wollman 
4055cbf3e08SGarrett Wollman 			rt = rtalloc1((struct sockaddr *)&icmpsrc, 0,
4065cbf3e08SGarrett Wollman 				      RTF_CLONING | RTF_PRCLONING);
4075cbf3e08SGarrett Wollman 			if (rt && (rt->rt_flags & RTF_HOST)
4085cbf3e08SGarrett Wollman 			    && !(rt->rt_rmx.rmx_locks & RTV_MTU)) {
4095cbf3e08SGarrett Wollman 				mtu = ntohs(icp->icmp_nextmtu);
4105cbf3e08SGarrett Wollman 				if (!mtu)
4115cbf3e08SGarrett Wollman 					mtu = ip_next_mtu(rt->rt_rmx.rmx_mtu,
4125cbf3e08SGarrett Wollman 							  1);
413be070f43SGarrett Wollman #ifdef DEBUG_MTUDISC
414be070f43SGarrett Wollman 				printf("MTU for %s reduced to %d\n",
415be070f43SGarrett Wollman 					inet_ntoa(icmpsrc.sin_addr), mtu);
416be070f43SGarrett Wollman #endif
417be070f43SGarrett Wollman 				if (mtu < 296) {
418b7a44e34SGarrett Wollman 					/* rt->rt_rmx.rmx_mtu =
419b7a44e34SGarrett Wollman 						rt->rt_ifp->if_mtu; */
4205cbf3e08SGarrett Wollman 					rt->rt_rmx.rmx_locks |= RTV_MTU;
4215cbf3e08SGarrett Wollman 				} else if (rt->rt_rmx.rmx_mtu > mtu) {
4225cbf3e08SGarrett Wollman 					rt->rt_rmx.rmx_mtu = mtu;
4235cbf3e08SGarrett Wollman 				}
4245cbf3e08SGarrett Wollman 			}
4255cbf3e08SGarrett Wollman 			if (rt)
4265cbf3e08SGarrett Wollman 				RTFREE(rt);
4275cbf3e08SGarrett Wollman 		}
4285cbf3e08SGarrett Wollman 
429b7a44e34SGarrett Wollman #endif
4306a800098SYoshinobu Inoue 		/*
4316a800098SYoshinobu Inoue 		 * XXX if the packet contains [IPv4 AH TCP], we can't make a
4326a800098SYoshinobu Inoue 		 * notification to TCP layer.
4336a800098SYoshinobu Inoue 		 */
434623ae52eSPoul-Henning Kamp 		ctlfunc = inetsw[ip_protox[icp->icmp_ip.ip_p]].pr_ctlinput;
435623ae52eSPoul-Henning Kamp 		if (ctlfunc)
436df8bae1dSRodney W. Grimes 			(*ctlfunc)(code, (struct sockaddr *)&icmpsrc,
437b62d102cSBruce Evans 				   (void *)&icp->icmp_ip);
438df8bae1dSRodney W. Grimes 		break;
439df8bae1dSRodney W. Grimes 
440df8bae1dSRodney W. Grimes 	badcode:
441df8bae1dSRodney W. Grimes 		icmpstat.icps_badcode++;
442df8bae1dSRodney W. Grimes 		break;
443df8bae1dSRodney W. Grimes 
444df8bae1dSRodney W. Grimes 	case ICMP_ECHO:
4457022ea0aSGarrett Wollman 		if (!icmpbmcastecho
446d311884fSDavid Greenman 		    && (m->m_flags & (M_MCAST | M_BCAST)) != 0) {
4477022ea0aSGarrett Wollman 			icmpstat.icps_bmcastecho++;
4487022ea0aSGarrett Wollman 			break;
4497022ea0aSGarrett Wollman 		}
450df8bae1dSRodney W. Grimes 		icp->icmp_type = ICMP_ECHOREPLY;
451a57815efSBosko Milekic 		if (badport_bandlim(BANDLIM_ICMP_ECHO) < 0)
45209f81a46SBosko Milekic 			goto freeit;
45309f81a46SBosko Milekic 		else
454df8bae1dSRodney W. Grimes 			goto reflect;
455df8bae1dSRodney W. Grimes 
456df8bae1dSRodney W. Grimes 	case ICMP_TSTAMP:
457fe0fb8abSGarrett Wollman 		if (!icmpbmcastecho
458d311884fSDavid Greenman 		    && (m->m_flags & (M_MCAST | M_BCAST)) != 0) {
459fe0fb8abSGarrett Wollman 			icmpstat.icps_bmcasttstamp++;
460fe0fb8abSGarrett Wollman 			break;
461fe0fb8abSGarrett Wollman 		}
462df8bae1dSRodney W. Grimes 		if (icmplen < ICMP_TSLEN) {
463df8bae1dSRodney W. Grimes 			icmpstat.icps_badlen++;
464df8bae1dSRodney W. Grimes 			break;
465df8bae1dSRodney W. Grimes 		}
466df8bae1dSRodney W. Grimes 		icp->icmp_type = ICMP_TSTAMPREPLY;
467df8bae1dSRodney W. Grimes 		icp->icmp_rtime = iptime();
468df8bae1dSRodney W. Grimes 		icp->icmp_ttime = icp->icmp_rtime;	/* bogus, do later! */
469a57815efSBosko Milekic 		if (badport_bandlim(BANDLIM_ICMP_TSTAMP) < 0)
47009f81a46SBosko Milekic 			goto freeit;
47109f81a46SBosko Milekic 		else
472df8bae1dSRodney W. Grimes 			goto reflect;
473df8bae1dSRodney W. Grimes 
474df8bae1dSRodney W. Grimes 	case ICMP_MASKREQ:
475df8bae1dSRodney W. Grimes 		if (icmpmaskrepl == 0)
476df8bae1dSRodney W. Grimes 			break;
477df8bae1dSRodney W. Grimes 		/*
478df8bae1dSRodney W. Grimes 		 * We are not able to respond with all ones broadcast
479df8bae1dSRodney W. Grimes 		 * unless we receive it over a point-to-point interface.
480df8bae1dSRodney W. Grimes 		 */
481df8bae1dSRodney W. Grimes 		if (icmplen < ICMP_MASKLEN)
482df8bae1dSRodney W. Grimes 			break;
483df8bae1dSRodney W. Grimes 		switch (ip->ip_dst.s_addr) {
484df8bae1dSRodney W. Grimes 
485df8bae1dSRodney W. Grimes 		case INADDR_BROADCAST:
486df8bae1dSRodney W. Grimes 		case INADDR_ANY:
487df8bae1dSRodney W. Grimes 			icmpdst.sin_addr = ip->ip_src;
488df8bae1dSRodney W. Grimes 			break;
489df8bae1dSRodney W. Grimes 
490df8bae1dSRodney W. Grimes 		default:
491df8bae1dSRodney W. Grimes 			icmpdst.sin_addr = ip->ip_dst;
492df8bae1dSRodney W. Grimes 		}
493df8bae1dSRodney W. Grimes 		ia = (struct in_ifaddr *)ifaof_ifpforaddr(
494df8bae1dSRodney W. Grimes 			    (struct sockaddr *)&icmpdst, m->m_pkthdr.rcvif);
495df8bae1dSRodney W. Grimes 		if (ia == 0)
496df8bae1dSRodney W. Grimes 			break;
4977e6f7714SPoul-Henning Kamp 		if (ia->ia_ifp == 0)
4987e6f7714SPoul-Henning Kamp 			break;
499df8bae1dSRodney W. Grimes 		icp->icmp_type = ICMP_MASKREPLY;
500df8bae1dSRodney W. Grimes 		icp->icmp_mask = ia->ia_sockmask.sin_addr.s_addr;
501df8bae1dSRodney W. Grimes 		if (ip->ip_src.s_addr == 0) {
502df8bae1dSRodney W. Grimes 			if (ia->ia_ifp->if_flags & IFF_BROADCAST)
503df8bae1dSRodney W. Grimes 			    ip->ip_src = satosin(&ia->ia_broadaddr)->sin_addr;
504df8bae1dSRodney W. Grimes 			else if (ia->ia_ifp->if_flags & IFF_POINTOPOINT)
505df8bae1dSRodney W. Grimes 			    ip->ip_src = satosin(&ia->ia_dstaddr)->sin_addr;
506df8bae1dSRodney W. Grimes 		}
507df8bae1dSRodney W. Grimes reflect:
508df8bae1dSRodney W. Grimes 		ip->ip_len += hlen;	/* since ip_input deducts this */
509df8bae1dSRodney W. Grimes 		icmpstat.icps_reflect++;
510df8bae1dSRodney W. Grimes 		icmpstat.icps_outhist[icp->icmp_type]++;
511df8bae1dSRodney W. Grimes 		icmp_reflect(m);
512df8bae1dSRodney W. Grimes 		return;
513df8bae1dSRodney W. Grimes 
514df8bae1dSRodney W. Grimes 	case ICMP_REDIRECT:
51518d3153eSDag-Erling Smørgrav 		if (log_redirect) {
51618d3153eSDag-Erling Smørgrav 			u_long src, dst, gw;
51718d3153eSDag-Erling Smørgrav 
51818d3153eSDag-Erling Smørgrav 			src = ntohl(ip->ip_src.s_addr);
51918d3153eSDag-Erling Smørgrav 			dst = ntohl(icp->icmp_ip.ip_dst.s_addr);
52018d3153eSDag-Erling Smørgrav 			gw = ntohl(icp->icmp_gwaddr.s_addr);
52118d3153eSDag-Erling Smørgrav 			printf("icmp redirect from %d.%d.%d.%d: "
52218d3153eSDag-Erling Smørgrav 			       "%d.%d.%d.%d => %d.%d.%d.%d\n",
52318d3153eSDag-Erling Smørgrav 			       (int)(src >> 24), (int)((src >> 16) & 0xff),
52418d3153eSDag-Erling Smørgrav 			       (int)((src >> 8) & 0xff), (int)(src & 0xff),
52518d3153eSDag-Erling Smørgrav 			       (int)(dst >> 24), (int)((dst >> 16) & 0xff),
52618d3153eSDag-Erling Smørgrav 			       (int)((dst >> 8) & 0xff), (int)(dst & 0xff),
52718d3153eSDag-Erling Smørgrav 			       (int)(gw >> 24), (int)((gw >> 16) & 0xff),
52818d3153eSDag-Erling Smørgrav 			       (int)((gw >> 8) & 0xff), (int)(gw & 0xff));
52918d3153eSDag-Erling Smørgrav 		}
53018d3153eSDag-Erling Smørgrav 		if (drop_redirect)
53118d3153eSDag-Erling Smørgrav 			break;
532df8bae1dSRodney W. Grimes 		if (code > 3)
533df8bae1dSRodney W. Grimes 			goto badcode;
534df8bae1dSRodney W. Grimes 		if (icmplen < ICMP_ADVLENMIN || icmplen < ICMP_ADVLEN(icp) ||
5355e2d0696SGarrett Wollman 		    IP_VHL_HL(icp->icmp_ip.ip_vhl) < (sizeof(struct ip) >> 2)) {
536df8bae1dSRodney W. Grimes 			icmpstat.icps_badlen++;
537df8bae1dSRodney W. Grimes 			break;
538df8bae1dSRodney W. Grimes 		}
539df8bae1dSRodney W. Grimes 		/*
540df8bae1dSRodney W. Grimes 		 * Short circuit routing redirects to force
541df8bae1dSRodney W. Grimes 		 * immediate change in the kernel's routing
542df8bae1dSRodney W. Grimes 		 * tables.  The message is also handed to anyone
543df8bae1dSRodney W. Grimes 		 * listening on a raw socket (e.g. the routing
544df8bae1dSRodney W. Grimes 		 * daemon for use in updating its tables).
545df8bae1dSRodney W. Grimes 		 */
546df8bae1dSRodney W. Grimes 		icmpgw.sin_addr = ip->ip_src;
547df8bae1dSRodney W. Grimes 		icmpdst.sin_addr = icp->icmp_gwaddr;
548df8bae1dSRodney W. Grimes #ifdef	ICMPPRINTFS
5492b758395SGarrett Wollman 		if (icmpprintfs) {
5502b758395SGarrett Wollman 			char buf[4 * sizeof "123"];
5512b758395SGarrett Wollman 			strcpy(buf, inet_ntoa(icp->icmp_ip.ip_dst));
5522b758395SGarrett Wollman 
5532b758395SGarrett Wollman 			printf("redirect dst %s to %s\n",
5542b758395SGarrett Wollman 			       buf, inet_ntoa(icp->icmp_gwaddr));
5552b758395SGarrett Wollman 		}
556df8bae1dSRodney W. Grimes #endif
557df8bae1dSRodney W. Grimes 		icmpsrc.sin_addr = icp->icmp_ip.ip_dst;
558df8bae1dSRodney W. Grimes 		rtredirect((struct sockaddr *)&icmpsrc,
559df8bae1dSRodney W. Grimes 		  (struct sockaddr *)&icmpdst,
560df8bae1dSRodney W. Grimes 		  (struct sockaddr *)0, RTF_GATEWAY | RTF_HOST,
561df8bae1dSRodney W. Grimes 		  (struct sockaddr *)&icmpgw, (struct rtentry **)0);
562df8bae1dSRodney W. Grimes 		pfctlinput(PRC_REDIRECT_HOST, (struct sockaddr *)&icmpsrc);
5636a800098SYoshinobu Inoue #ifdef IPSEC
5646a800098SYoshinobu Inoue 		key_sa_routechange((struct sockaddr *)&icmpsrc);
5656a800098SYoshinobu Inoue #endif
566df8bae1dSRodney W. Grimes 		break;
567df8bae1dSRodney W. Grimes 
568df8bae1dSRodney W. Grimes 	/*
569df8bae1dSRodney W. Grimes 	 * No kernel processing for the following;
570df8bae1dSRodney W. Grimes 	 * just fall through to send to raw listener.
571df8bae1dSRodney W. Grimes 	 */
572df8bae1dSRodney W. Grimes 	case ICMP_ECHOREPLY:
573df8bae1dSRodney W. Grimes 	case ICMP_ROUTERADVERT:
574df8bae1dSRodney W. Grimes 	case ICMP_ROUTERSOLICIT:
575df8bae1dSRodney W. Grimes 	case ICMP_TSTAMPREPLY:
576df8bae1dSRodney W. Grimes 	case ICMP_IREQREPLY:
577df8bae1dSRodney W. Grimes 	case ICMP_MASKREPLY:
578df8bae1dSRodney W. Grimes 	default:
579df8bae1dSRodney W. Grimes 		break;
580df8bae1dSRodney W. Grimes 	}
581df8bae1dSRodney W. Grimes 
582df8bae1dSRodney W. Grimes raw:
583f0ffb944SJulian Elischer 	rip_input(m, off);
584df8bae1dSRodney W. Grimes 	return;
585df8bae1dSRodney W. Grimes 
586df8bae1dSRodney W. Grimes freeit:
587df8bae1dSRodney W. Grimes 	m_freem(m);
588df8bae1dSRodney W. Grimes }
589df8bae1dSRodney W. Grimes 
590df8bae1dSRodney W. Grimes /*
591df8bae1dSRodney W. Grimes  * Reflect the ip packet back to the source
592df8bae1dSRodney W. Grimes  */
5930312fbe9SPoul-Henning Kamp static void
594df8bae1dSRodney W. Grimes icmp_reflect(m)
595df8bae1dSRodney W. Grimes 	struct mbuf *m;
596df8bae1dSRodney W. Grimes {
597ca925d9cSJonathan Lemon 	struct ip *ip = mtod(m, struct ip *);
598ca925d9cSJonathan Lemon 	struct ifaddr *ifa;
599ca925d9cSJonathan Lemon 	struct in_ifaddr *ia;
600df8bae1dSRodney W. Grimes 	struct in_addr t;
601b5e8ce9fSBruce Evans 	struct mbuf *opts = 0;
6025e2d0696SGarrett Wollman 	int optlen = (IP_VHL_HL(ip->ip_vhl) << 2) - sizeof(struct ip);
603bd714208SRuslan Ermilov 	struct route *ro = NULL, rt;
604df8bae1dSRodney W. Grimes 
605df8bae1dSRodney W. Grimes 	if (!in_canforward(ip->ip_src) &&
606df8bae1dSRodney W. Grimes 	    ((ntohl(ip->ip_src.s_addr) & IN_CLASSA_NET) !=
607df8bae1dSRodney W. Grimes 	     (IN_LOOPBACKNET << IN_CLASSA_NSHIFT))) {
608df8bae1dSRodney W. Grimes 		m_freem(m);	/* Bad return address */
609bd714208SRuslan Ermilov 		icmpstat.icps_badaddr++;
610df8bae1dSRodney W. Grimes 		goto done;	/* Ip_output() will check for broadcast */
611df8bae1dSRodney W. Grimes 	}
612df8bae1dSRodney W. Grimes 	t = ip->ip_dst;
613df8bae1dSRodney W. Grimes 	ip->ip_dst = ip->ip_src;
614e3f406b3SRuslan Ermilov 	ro = &rt;
615e3f406b3SRuslan Ermilov 	bzero(ro, sizeof(*ro));
616df8bae1dSRodney W. Grimes 	/*
617df8bae1dSRodney W. Grimes 	 * If the incoming packet was addressed directly to us,
618df8bae1dSRodney W. Grimes 	 * use dst as the src for the reply.  Otherwise (broadcast
619df8bae1dSRodney W. Grimes 	 * or anonymous), use the address which corresponds
620df8bae1dSRodney W. Grimes 	 * to the incoming interface.
621df8bae1dSRodney W. Grimes 	 */
622ca925d9cSJonathan Lemon 	LIST_FOREACH(ia, INADDR_HASH(t.s_addr), ia_hash)
623df8bae1dSRodney W. Grimes 		if (t.s_addr == IA_SIN(ia)->sin_addr.s_addr)
624ca925d9cSJonathan Lemon 			goto match;
62584caf008SRuslan Ermilov 	if (m->m_pkthdr.rcvif != NULL &&
62684caf008SRuslan Ermilov 	    m->m_pkthdr.rcvif->if_flags & IFF_BROADCAST) {
627ca925d9cSJonathan Lemon 		TAILQ_FOREACH(ifa, &m->m_pkthdr.rcvif->if_addrhead, ifa_link) {
628ca925d9cSJonathan Lemon 			if (ifa->ifa_addr->sa_family != AF_INET)
629ca925d9cSJonathan Lemon 				continue;
630ca925d9cSJonathan Lemon 			ia = ifatoia(ifa);
631ca925d9cSJonathan Lemon 			if (satosin(&ia->ia_broadaddr)->sin_addr.s_addr ==
632ca925d9cSJonathan Lemon 			    t.s_addr)
633ca925d9cSJonathan Lemon 				goto match;
634df8bae1dSRodney W. Grimes 		}
635ca925d9cSJonathan Lemon 	}
636bd714208SRuslan Ermilov 	ia = ip_rtaddr(ip->ip_dst, ro);
637bd714208SRuslan Ermilov 	/* We need a route to do anything useful. */
6380d4bef5dSDima Dorfman 	if (ia == NULL) {
6390d4bef5dSDima Dorfman 		m_freem(m);
640bd714208SRuslan Ermilov 		icmpstat.icps_noroute++;
6410d4bef5dSDima Dorfman 		goto done;
6420d4bef5dSDima Dorfman 	}
643ca925d9cSJonathan Lemon match:
644df8bae1dSRodney W. Grimes 	t = IA_SIN(ia)->sin_addr;
645df8bae1dSRodney W. Grimes 	ip->ip_src = t;
6468ce3f3ddSRuslan Ermilov 	ip->ip_ttl = ip_defttl;
647df8bae1dSRodney W. Grimes 
648df8bae1dSRodney W. Grimes 	if (optlen > 0) {
649df8bae1dSRodney W. Grimes 		register u_char *cp;
650df8bae1dSRodney W. Grimes 		int opt, cnt;
651df8bae1dSRodney W. Grimes 		u_int len;
652df8bae1dSRodney W. Grimes 
653df8bae1dSRodney W. Grimes 		/*
654df8bae1dSRodney W. Grimes 		 * Retrieve any source routing from the incoming packet;
655df8bae1dSRodney W. Grimes 		 * add on any record-route or timestamp options.
656df8bae1dSRodney W. Grimes 		 */
657df8bae1dSRodney W. Grimes 		cp = (u_char *) (ip + 1);
658df8bae1dSRodney W. Grimes 		if ((opts = ip_srcroute()) == 0 &&
659df8bae1dSRodney W. Grimes 		    (opts = m_gethdr(M_DONTWAIT, MT_HEADER))) {
660df8bae1dSRodney W. Grimes 			opts->m_len = sizeof(struct in_addr);
661df8bae1dSRodney W. Grimes 			mtod(opts, struct in_addr *)->s_addr = 0;
662df8bae1dSRodney W. Grimes 		}
663df8bae1dSRodney W. Grimes 		if (opts) {
664df8bae1dSRodney W. Grimes #ifdef ICMPPRINTFS
665df8bae1dSRodney W. Grimes 		    if (icmpprintfs)
666df8bae1dSRodney W. Grimes 			    printf("icmp_reflect optlen %d rt %d => ",
667df8bae1dSRodney W. Grimes 				optlen, opts->m_len);
668df8bae1dSRodney W. Grimes #endif
669df8bae1dSRodney W. Grimes 		    for (cnt = optlen; cnt > 0; cnt -= len, cp += len) {
670df8bae1dSRodney W. Grimes 			    opt = cp[IPOPT_OPTVAL];
671df8bae1dSRodney W. Grimes 			    if (opt == IPOPT_EOL)
672df8bae1dSRodney W. Grimes 				    break;
673df8bae1dSRodney W. Grimes 			    if (opt == IPOPT_NOP)
674df8bae1dSRodney W. Grimes 				    len = 1;
675df8bae1dSRodney W. Grimes 			    else {
676707d00a3SJonathan Lemon 				    if (cnt < IPOPT_OLEN + sizeof(*cp))
677707d00a3SJonathan Lemon 					    break;
678df8bae1dSRodney W. Grimes 				    len = cp[IPOPT_OLEN];
679707d00a3SJonathan Lemon 				    if (len < IPOPT_OLEN + sizeof(*cp) ||
680707d00a3SJonathan Lemon 				        len > cnt)
681df8bae1dSRodney W. Grimes 					    break;
682df8bae1dSRodney W. Grimes 			    }
683df8bae1dSRodney W. Grimes 			    /*
684df8bae1dSRodney W. Grimes 			     * Should check for overflow, but it "can't happen"
685df8bae1dSRodney W. Grimes 			     */
686df8bae1dSRodney W. Grimes 			    if (opt == IPOPT_RR || opt == IPOPT_TS ||
687df8bae1dSRodney W. Grimes 				opt == IPOPT_SECURITY) {
688df8bae1dSRodney W. Grimes 				    bcopy((caddr_t)cp,
689df8bae1dSRodney W. Grimes 					mtod(opts, caddr_t) + opts->m_len, len);
690df8bae1dSRodney W. Grimes 				    opts->m_len += len;
691df8bae1dSRodney W. Grimes 			    }
692df8bae1dSRodney W. Grimes 		    }
693df8bae1dSRodney W. Grimes 		    /* Terminate & pad, if necessary */
694623ae52eSPoul-Henning Kamp 		    cnt = opts->m_len % 4;
695623ae52eSPoul-Henning Kamp 		    if (cnt) {
696df8bae1dSRodney W. Grimes 			    for (; cnt < 4; cnt++) {
697df8bae1dSRodney W. Grimes 				    *(mtod(opts, caddr_t) + opts->m_len) =
698df8bae1dSRodney W. Grimes 					IPOPT_EOL;
699df8bae1dSRodney W. Grimes 				    opts->m_len++;
700df8bae1dSRodney W. Grimes 			    }
701df8bae1dSRodney W. Grimes 		    }
702df8bae1dSRodney W. Grimes #ifdef ICMPPRINTFS
703df8bae1dSRodney W. Grimes 		    if (icmpprintfs)
704df8bae1dSRodney W. Grimes 			    printf("%d\n", opts->m_len);
705df8bae1dSRodney W. Grimes #endif
706df8bae1dSRodney W. Grimes 		}
707df8bae1dSRodney W. Grimes 		/*
708df8bae1dSRodney W. Grimes 		 * Now strip out original options by copying rest of first
709df8bae1dSRodney W. Grimes 		 * mbuf's data back, and adjust the IP length.
710df8bae1dSRodney W. Grimes 		 */
711df8bae1dSRodney W. Grimes 		ip->ip_len -= optlen;
7125e2d0696SGarrett Wollman 		ip->ip_vhl = IP_VHL_BORING;
713df8bae1dSRodney W. Grimes 		m->m_len -= optlen;
714df8bae1dSRodney W. Grimes 		if (m->m_flags & M_PKTHDR)
715df8bae1dSRodney W. Grimes 			m->m_pkthdr.len -= optlen;
716df8bae1dSRodney W. Grimes 		optlen += sizeof(struct ip);
717df8bae1dSRodney W. Grimes 		bcopy((caddr_t)ip + optlen, (caddr_t)(ip + 1),
718df8bae1dSRodney W. Grimes 			 (unsigned)(m->m_len - sizeof(struct ip)));
719df8bae1dSRodney W. Grimes 	}
720df8bae1dSRodney W. Grimes 	m->m_flags &= ~(M_BCAST|M_MCAST);
721bd714208SRuslan Ermilov 	icmp_send(m, opts, ro);
722df8bae1dSRodney W. Grimes done:
723df8bae1dSRodney W. Grimes 	if (opts)
724df8bae1dSRodney W. Grimes 		(void)m_free(opts);
725bd714208SRuslan Ermilov 	if (ro && ro->ro_rt)
726bd714208SRuslan Ermilov 		RTFREE(ro->ro_rt);
727df8bae1dSRodney W. Grimes }
728df8bae1dSRodney W. Grimes 
729df8bae1dSRodney W. Grimes /*
730df8bae1dSRodney W. Grimes  * Send an icmp packet back to the ip level,
731df8bae1dSRodney W. Grimes  * after supplying a checksum.
732df8bae1dSRodney W. Grimes  */
7330312fbe9SPoul-Henning Kamp static void
734bd714208SRuslan Ermilov icmp_send(m, opts, rt)
735df8bae1dSRodney W. Grimes 	register struct mbuf *m;
736df8bae1dSRodney W. Grimes 	struct mbuf *opts;
737bd714208SRuslan Ermilov 	struct route *rt;
738df8bae1dSRodney W. Grimes {
739df8bae1dSRodney W. Grimes 	register struct ip *ip = mtod(m, struct ip *);
740df8bae1dSRodney W. Grimes 	register int hlen;
741df8bae1dSRodney W. Grimes 	register struct icmp *icp;
742df8bae1dSRodney W. Grimes 
7435e2d0696SGarrett Wollman 	hlen = IP_VHL_HL(ip->ip_vhl) << 2;
744df8bae1dSRodney W. Grimes 	m->m_data += hlen;
745df8bae1dSRodney W. Grimes 	m->m_len -= hlen;
746df8bae1dSRodney W. Grimes 	icp = mtod(m, struct icmp *);
747df8bae1dSRodney W. Grimes 	icp->icmp_cksum = 0;
748df8bae1dSRodney W. Grimes 	icp->icmp_cksum = in_cksum(m, ip->ip_len - hlen);
749df8bae1dSRodney W. Grimes 	m->m_data -= hlen;
750df8bae1dSRodney W. Grimes 	m->m_len += hlen;
75194446a2eSArchie Cobbs 	m->m_pkthdr.rcvif = (struct ifnet *)0;
752df8bae1dSRodney W. Grimes #ifdef ICMPPRINTFS
7532b758395SGarrett Wollman 	if (icmpprintfs) {
7542b758395SGarrett Wollman 		char buf[4 * sizeof "123"];
7552b758395SGarrett Wollman 		strcpy(buf, inet_ntoa(ip->ip_dst));
7562b758395SGarrett Wollman 		printf("icmp_send dst %s src %s\n",
7572b758395SGarrett Wollman 		       buf, inet_ntoa(ip->ip_src));
7582b758395SGarrett Wollman 	}
759df8bae1dSRodney W. Grimes #endif
7605d846453SSam Leffler 	(void) ip_output(m, opts, rt, 0, NULL, NULL);
761df8bae1dSRodney W. Grimes }
762df8bae1dSRodney W. Grimes 
763df8bae1dSRodney W. Grimes n_time
764df8bae1dSRodney W. Grimes iptime()
765df8bae1dSRodney W. Grimes {
766df8bae1dSRodney W. Grimes 	struct timeval atv;
767df8bae1dSRodney W. Grimes 	u_long t;
768df8bae1dSRodney W. Grimes 
76916cd6db0SBill Fumerola 	getmicrotime(&atv);
770df8bae1dSRodney W. Grimes 	t = (atv.tv_sec % (24*60*60)) * 1000 + atv.tv_usec / 1000;
771df8bae1dSRodney W. Grimes 	return (htonl(t));
772df8bae1dSRodney W. Grimes }
773df8bae1dSRodney W. Grimes 
774b7a44e34SGarrett Wollman #if 1
7755cbf3e08SGarrett Wollman /*
7765cbf3e08SGarrett Wollman  * Return the next larger or smaller MTU plateau (table from RFC 1191)
7775cbf3e08SGarrett Wollman  * given current value MTU.  If DIR is less than zero, a larger plateau
7785cbf3e08SGarrett Wollman  * is returned; otherwise, a smaller value is returned.
7795cbf3e08SGarrett Wollman  */
780f708ef1bSPoul-Henning Kamp static int
7815cbf3e08SGarrett Wollman ip_next_mtu(mtu, dir)
7825cbf3e08SGarrett Wollman 	int mtu;
7835cbf3e08SGarrett Wollman 	int dir;
7845cbf3e08SGarrett Wollman {
7855cbf3e08SGarrett Wollman 	static int mtutab[] = {
7865cbf3e08SGarrett Wollman 		65535, 32000, 17914, 8166, 4352, 2002, 1492, 1006, 508, 296,
7875cbf3e08SGarrett Wollman 		68, 0
7885cbf3e08SGarrett Wollman 	};
7895cbf3e08SGarrett Wollman 	int i;
7905cbf3e08SGarrett Wollman 
7915cbf3e08SGarrett Wollman 	for (i = 0; i < (sizeof mtutab) / (sizeof mtutab[0]); i++) {
7925cbf3e08SGarrett Wollman 		if (mtu >= mtutab[i])
7935cbf3e08SGarrett Wollman 			break;
7945cbf3e08SGarrett Wollman 	}
7955cbf3e08SGarrett Wollman 
7965cbf3e08SGarrett Wollman 	if (dir < 0) {
7975cbf3e08SGarrett Wollman 		if (i == 0) {
7985cbf3e08SGarrett Wollman 			return 0;
7995cbf3e08SGarrett Wollman 		} else {
8005cbf3e08SGarrett Wollman 			return mtutab[i - 1];
8015cbf3e08SGarrett Wollman 		}
8025cbf3e08SGarrett Wollman 	} else {
8035cbf3e08SGarrett Wollman 		if (mtutab[i] == 0) {
8045cbf3e08SGarrett Wollman 			return 0;
8055cbf3e08SGarrett Wollman 		} else if(mtu > mtutab[i]) {
8065cbf3e08SGarrett Wollman 			return mtutab[i];
8075cbf3e08SGarrett Wollman 		} else {
8085cbf3e08SGarrett Wollman 			return mtutab[i + 1];
8095cbf3e08SGarrett Wollman 		}
8105cbf3e08SGarrett Wollman 	}
8115cbf3e08SGarrett Wollman }
812b7a44e34SGarrett Wollman #endif
81351508de1SMatthew Dillon 
81451508de1SMatthew Dillon 
81551508de1SMatthew Dillon /*
81651508de1SMatthew Dillon  * badport_bandlim() - check for ICMP bandwidth limit
81751508de1SMatthew Dillon  *
81851508de1SMatthew Dillon  *	Return 0 if it is ok to send an ICMP error response, -1 if we have
81951508de1SMatthew Dillon  *	hit our bandwidth limit and it is not ok.
82051508de1SMatthew Dillon  *
82151508de1SMatthew Dillon  *	If icmplim is <= 0, the feature is disabled and 0 is returned.
82251508de1SMatthew Dillon  *
82351508de1SMatthew Dillon  *	For now we separate the TCP and UDP subsystems w/ different 'which'
82451508de1SMatthew Dillon  *	values.  We may eventually remove this separation (and simplify the
82551508de1SMatthew Dillon  *	code further).
82651508de1SMatthew Dillon  *
82751508de1SMatthew Dillon  *	Note that the printing of the error message is delayed so we can
82851508de1SMatthew Dillon  *	properly print the icmp error rate that the system was trying to do
82951508de1SMatthew Dillon  *	(i.e. 22000/100 pps, etc...).  This can cause long delays in printing
83051508de1SMatthew Dillon  *	the 'final' error, but it doesn't make sense to solve the printing
83151508de1SMatthew Dillon  *	delay with more complex code.
83251508de1SMatthew Dillon  */
83351508de1SMatthew Dillon 
83451508de1SMatthew Dillon int
83551508de1SMatthew Dillon badport_bandlim(int which)
83651508de1SMatthew Dillon {
83709f81a46SBosko Milekic 	static int lticks[BANDLIM_MAX + 1];
83809f81a46SBosko Milekic 	static int lpackets[BANDLIM_MAX + 1];
83951508de1SMatthew Dillon 	int dticks;
84009f81a46SBosko Milekic 	const char *bandlimittype[] = {
84109f81a46SBosko Milekic 		"Limiting icmp unreach response",
84209f81a46SBosko Milekic 		"Limiting icmp ping response",
843a57815efSBosko Milekic 		"Limiting icmp tstamp response",
844a57815efSBosko Milekic 		"Limiting closed port RST response",
845a57815efSBosko Milekic 		"Limiting open port RST response"
84609f81a46SBosko Milekic 		};
84751508de1SMatthew Dillon 
84851508de1SMatthew Dillon 	/*
84951508de1SMatthew Dillon 	 * Return ok status if feature disabled or argument out of
85051508de1SMatthew Dillon 	 * ranage.
85151508de1SMatthew Dillon 	 */
85251508de1SMatthew Dillon 
85309f81a46SBosko Milekic 	if (icmplim <= 0 || which > BANDLIM_MAX || which < 0)
85451508de1SMatthew Dillon 		return(0);
85551508de1SMatthew Dillon 	dticks = ticks - lticks[which];
85651508de1SMatthew Dillon 
85751508de1SMatthew Dillon 	/*
85851508de1SMatthew Dillon 	 * reset stats when cumulative dt exceeds one second.
85951508de1SMatthew Dillon 	 */
86051508de1SMatthew Dillon 
86151508de1SMatthew Dillon 	if ((unsigned int)dticks > hz) {
8624f14ee00SDan Moschuk 		if (lpackets[which] > icmplim && icmplim_output) {
86309f81a46SBosko Milekic 			printf("%s from %d to %d packets per second\n",
86409f81a46SBosko Milekic 				bandlimittype[which],
86551508de1SMatthew Dillon 				lpackets[which],
86651508de1SMatthew Dillon 				icmplim
86751508de1SMatthew Dillon 			);
86851508de1SMatthew Dillon 		}
86951508de1SMatthew Dillon 		lticks[which] = ticks;
87051508de1SMatthew Dillon 		lpackets[which] = 0;
87151508de1SMatthew Dillon 	}
87251508de1SMatthew Dillon 
87351508de1SMatthew Dillon 	/*
87451508de1SMatthew Dillon 	 * bump packet count
87551508de1SMatthew Dillon 	 */
87651508de1SMatthew Dillon 
87751508de1SMatthew Dillon 	if (++lpackets[which] > icmplim) {
87851508de1SMatthew Dillon 		return(-1);
87951508de1SMatthew Dillon 	}
88051508de1SMatthew Dillon 	return(0);
88151508de1SMatthew Dillon }
88251508de1SMatthew Dillon 
883