xref: /freebsd/sys/netinet/ip_icmp.c (revision 0070e096d7d340aa9a934cf59b59865f5eecf8c8)
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 
6872a52a35SJonathan Lemon #include <machine/in_cksum.h>
6972a52a35SJonathan Lemon 
70df8bae1dSRodney W. Grimes /*
71df8bae1dSRodney W. Grimes  * ICMP routines: error generation, receive packet processing, and
72df8bae1dSRodney W. Grimes  * routines to turnaround packets back to the originator, and
73df8bae1dSRodney W. Grimes  * host table maintenance routines.
74df8bae1dSRodney W. Grimes  */
75df8bae1dSRodney W. Grimes 
76f708ef1bSPoul-Henning Kamp static struct	icmpstat icmpstat;
77c73d99b5SRuslan Ermilov SYSCTL_STRUCT(_net_inet_icmp, ICMPCTL_STATS, stats, CTLFLAG_RW,
780312fbe9SPoul-Henning Kamp 	&icmpstat, icmpstat, "");
790312fbe9SPoul-Henning Kamp 
800312fbe9SPoul-Henning Kamp static int	icmpmaskrepl = 0;
810312fbe9SPoul-Henning Kamp SYSCTL_INT(_net_inet_icmp, ICMPCTL_MASKREPL, maskrepl, CTLFLAG_RW,
820312fbe9SPoul-Henning Kamp 	&icmpmaskrepl, 0, "");
830312fbe9SPoul-Henning Kamp 
8418d3153eSDag-Erling Smørgrav static int	drop_redirect = 0;
8518d3153eSDag-Erling Smørgrav SYSCTL_INT(_net_inet_icmp, OID_AUTO, drop_redirect, CTLFLAG_RW,
8618d3153eSDag-Erling Smørgrav 	&drop_redirect, 0, "");
8718d3153eSDag-Erling Smørgrav 
886c3b5f69SDag-Erling Smørgrav static int	log_redirect = 0;
896c3b5f69SDag-Erling Smørgrav SYSCTL_INT(_net_inet_icmp, OID_AUTO, log_redirect, CTLFLAG_RW,
906c3b5f69SDag-Erling Smørgrav 	&log_redirect, 0, "");
916c3b5f69SDag-Erling Smørgrav 
92173c0f9fSWarner Losh static int      icmplim = 200;
9351508de1SMatthew Dillon SYSCTL_INT(_net_inet_icmp, ICMPCTL_ICMPLIM, icmplim, CTLFLAG_RW,
9451508de1SMatthew Dillon 	&icmplim, 0, "");
955fce7fc4SMatthew Dillon 
964f14ee00SDan Moschuk static int	icmplim_output = 1;
974f14ee00SDan Moschuk SYSCTL_INT(_net_inet_icmp, OID_AUTO, icmplim_output, CTLFLAG_RW,
984f14ee00SDan Moschuk 	&icmplim_output, 0, "");
9951508de1SMatthew Dillon 
1005fce7fc4SMatthew Dillon /*
1015fce7fc4SMatthew Dillon  * ICMP broadcast echo sysctl
1025fce7fc4SMatthew Dillon  */
1035fce7fc4SMatthew Dillon 
10461a4defdSJoseph Koshy static int	icmpbmcastecho = 0;
10518d3153eSDag-Erling Smørgrav SYSCTL_INT(_net_inet_icmp, OID_AUTO, bmcastecho, CTLFLAG_RW,
10618d3153eSDag-Erling Smørgrav 	&icmpbmcastecho, 0, "");
1077022ea0aSGarrett Wollman 
10851508de1SMatthew Dillon 
109df8bae1dSRodney W. Grimes #ifdef ICMPPRINTFS
110df8bae1dSRodney W. Grimes int	icmpprintfs = 0;
111df8bae1dSRodney W. Grimes #endif
112df8bae1dSRodney W. Grimes 
1134d77a549SAlfred Perlstein static void	icmp_reflect(struct mbuf *);
1144d77a549SAlfred Perlstein static void	icmp_send(struct mbuf *, struct mbuf *, struct route *);
1154d77a549SAlfred Perlstein static int	ip_next_mtu(int, int);
1160312fbe9SPoul-Henning Kamp 
117df8bae1dSRodney W. Grimes extern	struct protosw inetsw[];
118df8bae1dSRodney W. Grimes 
119df8bae1dSRodney W. Grimes /*
120df8bae1dSRodney W. Grimes  * Generate an error packet of type error
121df8bae1dSRodney W. Grimes  * in response to bad packet ip.
122df8bae1dSRodney W. Grimes  */
123df8bae1dSRodney W. Grimes void
124df8bae1dSRodney W. Grimes icmp_error(n, type, code, dest, destifp)
125df8bae1dSRodney W. Grimes 	struct mbuf *n;
126df8bae1dSRodney W. Grimes 	int type, code;
127df8bae1dSRodney W. Grimes 	n_long dest;
128df8bae1dSRodney W. Grimes 	struct ifnet *destifp;
129df8bae1dSRodney W. Grimes {
130df8bae1dSRodney W. Grimes 	register struct ip *oip = mtod(n, struct ip *), *nip;
1315e2d0696SGarrett Wollman 	register unsigned oiplen = IP_VHL_HL(oip->ip_vhl) << 2;
132df8bae1dSRodney W. Grimes 	register struct icmp *icp;
133df8bae1dSRodney W. Grimes 	register struct mbuf *m;
134df8bae1dSRodney W. Grimes 	unsigned icmplen;
135df8bae1dSRodney W. Grimes 
136df8bae1dSRodney W. Grimes #ifdef ICMPPRINTFS
137df8bae1dSRodney W. Grimes 	if (icmpprintfs)
138623ae52eSPoul-Henning Kamp 		printf("icmp_error(%p, %x, %d)\n", oip, type, code);
139df8bae1dSRodney W. Grimes #endif
140df8bae1dSRodney W. Grimes 	if (type != ICMP_REDIRECT)
141df8bae1dSRodney W. Grimes 		icmpstat.icps_error++;
142df8bae1dSRodney W. Grimes 	/*
143df8bae1dSRodney W. Grimes 	 * Don't send error if not the first fragment of message.
144df8bae1dSRodney W. Grimes 	 * Don't error if the old packet protocol was ICMP
145df8bae1dSRodney W. Grimes 	 * error message, only known informational types.
146df8bae1dSRodney W. Grimes 	 */
147df8bae1dSRodney W. Grimes 	if (oip->ip_off &~ (IP_MF|IP_DF))
148df8bae1dSRodney W. Grimes 		goto freeit;
149df8bae1dSRodney W. Grimes 	if (oip->ip_p == IPPROTO_ICMP && type != ICMP_REDIRECT &&
150df8bae1dSRodney W. Grimes 	  n->m_len >= oiplen + ICMP_MINLEN &&
151df8bae1dSRodney W. Grimes 	  !ICMP_INFOTYPE(((struct icmp *)((caddr_t)oip + oiplen))->icmp_type)) {
152df8bae1dSRodney W. Grimes 		icmpstat.icps_oldicmp++;
153df8bae1dSRodney W. Grimes 		goto freeit;
154df8bae1dSRodney W. Grimes 	}
155df8bae1dSRodney W. Grimes 	/* Don't send error in response to a multicast or broadcast packet */
156df8bae1dSRodney W. Grimes 	if (n->m_flags & (M_BCAST|M_MCAST))
157df8bae1dSRodney W. Grimes 		goto freeit;
158df8bae1dSRodney W. Grimes 	/*
159df8bae1dSRodney W. Grimes 	 * First, formulate icmp message
160df8bae1dSRodney W. Grimes 	 */
161df8bae1dSRodney W. Grimes 	m = m_gethdr(M_DONTWAIT, MT_HEADER);
162df8bae1dSRodney W. Grimes 	if (m == NULL)
163df8bae1dSRodney W. Grimes 		goto freeit;
1640070e096SRobert Watson #ifdef MAC
1650070e096SRobert Watson 	mac_create_mbuf_netlayer(n, m);
1660070e096SRobert Watson #endif
1671d027522SRuslan Ermilov 	icmplen = min(oiplen + 8, oip->ip_len);
168bfef7ed4SIan Dowse 	if (icmplen < sizeof(struct ip))
169bfef7ed4SIan Dowse 		panic("icmp_error: bad length");
170df8bae1dSRodney W. Grimes 	m->m_len = icmplen + ICMP_MINLEN;
171df8bae1dSRodney W. Grimes 	MH_ALIGN(m, m->m_len);
172df8bae1dSRodney W. Grimes 	icp = mtod(m, struct icmp *);
173df8bae1dSRodney W. Grimes 	if ((u_int)type > ICMP_MAXTYPE)
174df8bae1dSRodney W. Grimes 		panic("icmp_error");
175df8bae1dSRodney W. Grimes 	icmpstat.icps_outhist[type]++;
176df8bae1dSRodney W. Grimes 	icp->icmp_type = type;
177df8bae1dSRodney W. Grimes 	if (type == ICMP_REDIRECT)
178df8bae1dSRodney W. Grimes 		icp->icmp_gwaddr.s_addr = dest;
179df8bae1dSRodney W. Grimes 	else {
180df8bae1dSRodney W. Grimes 		icp->icmp_void = 0;
181df8bae1dSRodney W. Grimes 		/*
182df8bae1dSRodney W. Grimes 		 * The following assignments assume an overlay with the
183df8bae1dSRodney W. Grimes 		 * zeroed icmp_void field.
184df8bae1dSRodney W. Grimes 		 */
185df8bae1dSRodney W. Grimes 		if (type == ICMP_PARAMPROB) {
186df8bae1dSRodney W. Grimes 			icp->icmp_pptr = code;
187df8bae1dSRodney W. Grimes 			code = 0;
188df8bae1dSRodney W. Grimes 		} else if (type == ICMP_UNREACH &&
189df8bae1dSRodney W. Grimes 			code == ICMP_UNREACH_NEEDFRAG && destifp) {
190df8bae1dSRodney W. Grimes 			icp->icmp_nextmtu = htons(destifp->if_mtu);
191df8bae1dSRodney W. Grimes 		}
192df8bae1dSRodney W. Grimes 	}
193df8bae1dSRodney W. Grimes 
194df8bae1dSRodney W. Grimes 	icp->icmp_code = code;
195bfef7ed4SIan Dowse 	m_copydata(n, 0, icmplen, (caddr_t)&icp->icmp_ip);
196df8bae1dSRodney W. Grimes 	nip = &icp->icmp_ip;
19704287599SRuslan Ermilov 
19804287599SRuslan Ermilov 	/*
19904287599SRuslan Ermilov 	 * Convert fields to network representation.
20004287599SRuslan Ermilov 	 */
201fd8e4ebcSMike Barcroft 	nip->ip_len = htons(nip->ip_len);
202fd8e4ebcSMike Barcroft 	nip->ip_off = htons(nip->ip_off);
203df8bae1dSRodney W. Grimes 
204df8bae1dSRodney W. Grimes 	/*
205df8bae1dSRodney W. Grimes 	 * Now, copy old ip header (without options)
206df8bae1dSRodney W. Grimes 	 * in front of icmp message.
207df8bae1dSRodney W. Grimes 	 */
208df8bae1dSRodney W. Grimes 	if (m->m_data - sizeof(struct ip) < m->m_pktdat)
209df8bae1dSRodney W. Grimes 		panic("icmp len");
210df8bae1dSRodney W. Grimes 	m->m_data -= sizeof(struct ip);
211df8bae1dSRodney W. Grimes 	m->m_len += sizeof(struct ip);
212df8bae1dSRodney W. Grimes 	m->m_pkthdr.len = m->m_len;
213df8bae1dSRodney W. Grimes 	m->m_pkthdr.rcvif = n->m_pkthdr.rcvif;
214df8bae1dSRodney W. Grimes 	nip = mtod(m, struct ip *);
215df8bae1dSRodney W. Grimes 	bcopy((caddr_t)oip, (caddr_t)nip, sizeof(struct ip));
216df8bae1dSRodney W. Grimes 	nip->ip_len = m->m_len;
2175e2d0696SGarrett Wollman 	nip->ip_vhl = IP_VHL_BORING;
218df8bae1dSRodney W. Grimes 	nip->ip_p = IPPROTO_ICMP;
219df8bae1dSRodney W. Grimes 	nip->ip_tos = 0;
220df8bae1dSRodney W. Grimes 	icmp_reflect(m);
221df8bae1dSRodney W. Grimes 
222df8bae1dSRodney W. Grimes freeit:
223df8bae1dSRodney W. Grimes 	m_freem(n);
224df8bae1dSRodney W. Grimes }
225df8bae1dSRodney W. Grimes 
226df8bae1dSRodney W. Grimes static struct sockaddr_in icmpsrc = { sizeof (struct sockaddr_in), AF_INET };
227df8bae1dSRodney W. Grimes static struct sockaddr_in icmpdst = { sizeof (struct sockaddr_in), AF_INET };
228df8bae1dSRodney W. Grimes static struct sockaddr_in icmpgw = { sizeof (struct sockaddr_in), AF_INET };
229df8bae1dSRodney W. Grimes 
230df8bae1dSRodney W. Grimes /*
231df8bae1dSRodney W. Grimes  * Process a received ICMP message.
232df8bae1dSRodney W. Grimes  */
233df8bae1dSRodney W. Grimes void
234f0ffb944SJulian Elischer icmp_input(m, off)
235df8bae1dSRodney W. Grimes 	register struct mbuf *m;
236f0ffb944SJulian Elischer 	int off;
237df8bae1dSRodney W. Grimes {
2386a800098SYoshinobu Inoue 	int hlen = off;
239df8bae1dSRodney W. Grimes 	register struct icmp *icp;
240df8bae1dSRodney W. Grimes 	register struct ip *ip = mtod(m, struct ip *);
241df8bae1dSRodney W. Grimes 	int icmplen = ip->ip_len;
242df8bae1dSRodney W. Grimes 	register int i;
243df8bae1dSRodney W. Grimes 	struct in_ifaddr *ia;
2444d77a549SAlfred Perlstein 	void (*ctlfunc)(int, struct sockaddr *, void *);
245df8bae1dSRodney W. Grimes 	int code;
246df8bae1dSRodney W. Grimes 
247df8bae1dSRodney W. Grimes 	/*
248df8bae1dSRodney W. Grimes 	 * Locate icmp structure in mbuf, and check
249df8bae1dSRodney W. Grimes 	 * that not corrupted and of at least minimum length.
250df8bae1dSRodney W. Grimes 	 */
251df8bae1dSRodney W. Grimes #ifdef ICMPPRINTFS
2522b758395SGarrett Wollman 	if (icmpprintfs) {
2532b758395SGarrett Wollman 		char buf[4 * sizeof "123"];
2542b758395SGarrett Wollman 		strcpy(buf, inet_ntoa(ip->ip_src));
2552b758395SGarrett Wollman 		printf("icmp_input from %s to %s, len %d\n",
2562b758395SGarrett Wollman 		       buf, inet_ntoa(ip->ip_dst), icmplen);
2572b758395SGarrett Wollman 	}
258df8bae1dSRodney W. Grimes #endif
259df8bae1dSRodney W. Grimes 	if (icmplen < ICMP_MINLEN) {
260df8bae1dSRodney W. Grimes 		icmpstat.icps_tooshort++;
261df8bae1dSRodney W. Grimes 		goto freeit;
262df8bae1dSRodney W. Grimes 	}
263df8bae1dSRodney W. Grimes 	i = hlen + min(icmplen, ICMP_ADVLENMIN);
264df8bae1dSRodney W. Grimes 	if (m->m_len < i && (m = m_pullup(m, i)) == 0)  {
265df8bae1dSRodney W. Grimes 		icmpstat.icps_tooshort++;
266df8bae1dSRodney W. Grimes 		return;
267df8bae1dSRodney W. Grimes 	}
268df8bae1dSRodney W. Grimes 	ip = mtod(m, struct ip *);
269df8bae1dSRodney W. Grimes 	m->m_len -= hlen;
270df8bae1dSRodney W. Grimes 	m->m_data += hlen;
271df8bae1dSRodney W. Grimes 	icp = mtod(m, struct icmp *);
272df8bae1dSRodney W. Grimes 	if (in_cksum(m, icmplen)) {
273df8bae1dSRodney W. Grimes 		icmpstat.icps_checksum++;
274df8bae1dSRodney W. Grimes 		goto freeit;
275df8bae1dSRodney W. Grimes 	}
276df8bae1dSRodney W. Grimes 	m->m_len += hlen;
277df8bae1dSRodney W. Grimes 	m->m_data -= hlen;
278df8bae1dSRodney W. Grimes 
2796a800098SYoshinobu Inoue 	if (m->m_pkthdr.rcvif && m->m_pkthdr.rcvif->if_type == IFT_FAITH) {
2806a800098SYoshinobu Inoue 		/*
2816a800098SYoshinobu Inoue 		 * Deliver very specific ICMP type only.
2826a800098SYoshinobu Inoue 		 */
2836a800098SYoshinobu Inoue 		switch (icp->icmp_type) {
2846a800098SYoshinobu Inoue 		case ICMP_UNREACH:
2856a800098SYoshinobu Inoue 		case ICMP_TIMXCEED:
2866a800098SYoshinobu Inoue 			break;
2876a800098SYoshinobu Inoue 		default:
2886a800098SYoshinobu Inoue 			goto freeit;
2896a800098SYoshinobu Inoue 		}
2906a800098SYoshinobu Inoue 	}
2916a800098SYoshinobu Inoue 
292df8bae1dSRodney W. Grimes #ifdef ICMPPRINTFS
293df8bae1dSRodney W. Grimes 	if (icmpprintfs)
294df8bae1dSRodney W. Grimes 		printf("icmp_input, type %d code %d\n", icp->icmp_type,
295df8bae1dSRodney W. Grimes 		    icp->icmp_code);
296df8bae1dSRodney W. Grimes #endif
2975b7ee6edSGarrett Wollman 
2985b7ee6edSGarrett Wollman 	/*
2995b7ee6edSGarrett Wollman 	 * Message type specific processing.
3005b7ee6edSGarrett Wollman 	 */
301df8bae1dSRodney W. Grimes 	if (icp->icmp_type > ICMP_MAXTYPE)
302df8bae1dSRodney W. Grimes 		goto raw;
303df8bae1dSRodney W. Grimes 	icmpstat.icps_inhist[icp->icmp_type]++;
304df8bae1dSRodney W. Grimes 	code = icp->icmp_code;
305df8bae1dSRodney W. Grimes 	switch (icp->icmp_type) {
306df8bae1dSRodney W. Grimes 
307df8bae1dSRodney W. Grimes 	case ICMP_UNREACH:
308df8bae1dSRodney W. Grimes 		switch (code) {
309df8bae1dSRodney W. Grimes 			case ICMP_UNREACH_NET:
310df8bae1dSRodney W. Grimes 			case ICMP_UNREACH_HOST:
311df8bae1dSRodney W. Grimes 			case ICMP_UNREACH_SRCFAIL:
312e4bb5b05SJonathan Lemon 			case ICMP_UNREACH_NET_UNKNOWN:
313e4bb5b05SJonathan Lemon 			case ICMP_UNREACH_HOST_UNKNOWN:
314e4bb5b05SJonathan Lemon 			case ICMP_UNREACH_ISOLATED:
315e4bb5b05SJonathan Lemon 			case ICMP_UNREACH_TOSNET:
316e4bb5b05SJonathan Lemon 			case ICMP_UNREACH_TOSHOST:
317e4bb5b05SJonathan Lemon 			case ICMP_UNREACH_HOST_PRECEDENCE:
318e4bb5b05SJonathan Lemon 			case ICMP_UNREACH_PRECEDENCE_CUTOFF:
319e4bb5b05SJonathan Lemon 				code = PRC_UNREACH_NET;
320df8bae1dSRodney W. Grimes 				break;
321df8bae1dSRodney W. Grimes 
322df8bae1dSRodney W. Grimes 			case ICMP_UNREACH_NEEDFRAG:
323df8bae1dSRodney W. Grimes 				code = PRC_MSGSIZE;
324df8bae1dSRodney W. Grimes 				break;
325df8bae1dSRodney W. Grimes 
326e4bb5b05SJonathan Lemon 			/*
327e4bb5b05SJonathan Lemon 			 * RFC 1122, Sections 3.2.2.1 and 4.2.3.9.
328e4bb5b05SJonathan Lemon 			 * Treat subcodes 2,3 as immediate RST
329e4bb5b05SJonathan Lemon 			 */
330e4bb5b05SJonathan Lemon 			case ICMP_UNREACH_PROTOCOL:
331e4bb5b05SJonathan Lemon 			case ICMP_UNREACH_PORT:
332b77d155dSJesper Skriver 				code = PRC_UNREACH_PORT;
333b11d7a4aSPoul-Henning Kamp 				break;
33490fcbbd6SPoul-Henning Kamp 
33590fcbbd6SPoul-Henning Kamp 			case ICMP_UNREACH_NET_PROHIB:
33690fcbbd6SPoul-Henning Kamp 			case ICMP_UNREACH_HOST_PROHIB:
3379c4b2574SPaul Traina 			case ICMP_UNREACH_FILTER_PROHIB:
33890fcbbd6SPoul-Henning Kamp 				code = PRC_UNREACH_ADMIN_PROHIB;
339b11d7a4aSPoul-Henning Kamp 				break;
340b11d7a4aSPoul-Henning Kamp 
341df8bae1dSRodney W. Grimes 			default:
342df8bae1dSRodney W. Grimes 				goto badcode;
343df8bae1dSRodney W. Grimes 		}
344df8bae1dSRodney W. Grimes 		goto deliver;
345df8bae1dSRodney W. Grimes 
346df8bae1dSRodney W. Grimes 	case ICMP_TIMXCEED:
347df8bae1dSRodney W. Grimes 		if (code > 1)
348df8bae1dSRodney W. Grimes 			goto badcode;
349df8bae1dSRodney W. Grimes 		code += PRC_TIMXCEED_INTRANS;
350df8bae1dSRodney W. Grimes 		goto deliver;
351df8bae1dSRodney W. Grimes 
352df8bae1dSRodney W. Grimes 	case ICMP_PARAMPROB:
353df8bae1dSRodney W. Grimes 		if (code > 1)
354df8bae1dSRodney W. Grimes 			goto badcode;
355df8bae1dSRodney W. Grimes 		code = PRC_PARAMPROB;
356df8bae1dSRodney W. Grimes 		goto deliver;
357df8bae1dSRodney W. Grimes 
358df8bae1dSRodney W. Grimes 	case ICMP_SOURCEQUENCH:
359df8bae1dSRodney W. Grimes 		if (code)
360df8bae1dSRodney W. Grimes 			goto badcode;
361df8bae1dSRodney W. Grimes 		code = PRC_QUENCH;
362df8bae1dSRodney W. Grimes 	deliver:
363df8bae1dSRodney W. Grimes 		/*
364df8bae1dSRodney W. Grimes 		 * Problem with datagram; advise higher level routines.
365df8bae1dSRodney W. Grimes 		 */
366df8bae1dSRodney W. Grimes 		if (icmplen < ICMP_ADVLENMIN || icmplen < ICMP_ADVLEN(icp) ||
3675e2d0696SGarrett Wollman 		    IP_VHL_HL(icp->icmp_ip.ip_vhl) < (sizeof(struct ip) >> 2)) {
368df8bae1dSRodney W. Grimes 			icmpstat.icps_badlen++;
369df8bae1dSRodney W. Grimes 			goto freeit;
370df8bae1dSRodney W. Grimes 		}
371fd8e4ebcSMike Barcroft 		icp->icmp_ip.ip_len = ntohs(icp->icmp_ip.ip_len);
3725b7ee6edSGarrett Wollman 		/* Discard ICMP's in response to multicast packets */
3735b7ee6edSGarrett Wollman 		if (IN_MULTICAST(ntohl(icp->icmp_ip.ip_dst.s_addr)))
3745b7ee6edSGarrett Wollman 			goto badcode;
375df8bae1dSRodney W. Grimes #ifdef ICMPPRINTFS
376df8bae1dSRodney W. Grimes 		if (icmpprintfs)
377df8bae1dSRodney W. Grimes 			printf("deliver to protocol %d\n", icp->icmp_ip.ip_p);
378df8bae1dSRodney W. Grimes #endif
379df8bae1dSRodney W. Grimes 		icmpsrc.sin_addr = icp->icmp_ip.ip_dst;
380b7a44e34SGarrett Wollman #if 1
3815cbf3e08SGarrett Wollman 		/*
3825cbf3e08SGarrett Wollman 		 * MTU discovery:
3835cbf3e08SGarrett Wollman 		 * If we got a needfrag and there is a host route to the
3845cbf3e08SGarrett Wollman 		 * original destination, and the MTU is not locked, then
3855cbf3e08SGarrett Wollman 		 * set the MTU in the route to the suggested new value
3865cbf3e08SGarrett Wollman 		 * (if given) and then notify as usual.  The ULPs will
3875cbf3e08SGarrett Wollman 		 * notice that the MTU has changed and adapt accordingly.
3885cbf3e08SGarrett Wollman 		 * If no new MTU was suggested, then we guess a new one
3895cbf3e08SGarrett Wollman 		 * less than the current value.  If the new MTU is
3905cbf3e08SGarrett Wollman 		 * unreasonably small (arbitrarily set at 296), then
3915cbf3e08SGarrett Wollman 		 * we reset the MTU to the interface value and enable the
3925cbf3e08SGarrett Wollman 		 * lock bit, indicating that we are no longer doing MTU
3935cbf3e08SGarrett Wollman 		 * discovery.
3945cbf3e08SGarrett Wollman 		 */
3955cbf3e08SGarrett Wollman 		if (code == PRC_MSGSIZE) {
3965cbf3e08SGarrett Wollman 			struct rtentry *rt;
3975cbf3e08SGarrett Wollman 			int mtu;
3985cbf3e08SGarrett Wollman 
3995cbf3e08SGarrett Wollman 			rt = rtalloc1((struct sockaddr *)&icmpsrc, 0,
4005cbf3e08SGarrett Wollman 				      RTF_CLONING | RTF_PRCLONING);
4015cbf3e08SGarrett Wollman 			if (rt && (rt->rt_flags & RTF_HOST)
4025cbf3e08SGarrett Wollman 			    && !(rt->rt_rmx.rmx_locks & RTV_MTU)) {
4035cbf3e08SGarrett Wollman 				mtu = ntohs(icp->icmp_nextmtu);
4045cbf3e08SGarrett Wollman 				if (!mtu)
4055cbf3e08SGarrett Wollman 					mtu = ip_next_mtu(rt->rt_rmx.rmx_mtu,
4065cbf3e08SGarrett Wollman 							  1);
407be070f43SGarrett Wollman #ifdef DEBUG_MTUDISC
408be070f43SGarrett Wollman 				printf("MTU for %s reduced to %d\n",
409be070f43SGarrett Wollman 					inet_ntoa(icmpsrc.sin_addr), mtu);
410be070f43SGarrett Wollman #endif
411be070f43SGarrett Wollman 				if (mtu < 296) {
412b7a44e34SGarrett Wollman 					/* rt->rt_rmx.rmx_mtu =
413b7a44e34SGarrett Wollman 						rt->rt_ifp->if_mtu; */
4145cbf3e08SGarrett Wollman 					rt->rt_rmx.rmx_locks |= RTV_MTU;
4155cbf3e08SGarrett Wollman 				} else if (rt->rt_rmx.rmx_mtu > mtu) {
4165cbf3e08SGarrett Wollman 					rt->rt_rmx.rmx_mtu = mtu;
4175cbf3e08SGarrett Wollman 				}
4185cbf3e08SGarrett Wollman 			}
4195cbf3e08SGarrett Wollman 			if (rt)
4205cbf3e08SGarrett Wollman 				RTFREE(rt);
4215cbf3e08SGarrett Wollman 		}
4225cbf3e08SGarrett Wollman 
423b7a44e34SGarrett Wollman #endif
4246a800098SYoshinobu Inoue 		/*
4256a800098SYoshinobu Inoue 		 * XXX if the packet contains [IPv4 AH TCP], we can't make a
4266a800098SYoshinobu Inoue 		 * notification to TCP layer.
4276a800098SYoshinobu Inoue 		 */
428623ae52eSPoul-Henning Kamp 		ctlfunc = inetsw[ip_protox[icp->icmp_ip.ip_p]].pr_ctlinput;
429623ae52eSPoul-Henning Kamp 		if (ctlfunc)
430df8bae1dSRodney W. Grimes 			(*ctlfunc)(code, (struct sockaddr *)&icmpsrc,
431b62d102cSBruce Evans 				   (void *)&icp->icmp_ip);
432df8bae1dSRodney W. Grimes 		break;
433df8bae1dSRodney W. Grimes 
434df8bae1dSRodney W. Grimes 	badcode:
435df8bae1dSRodney W. Grimes 		icmpstat.icps_badcode++;
436df8bae1dSRodney W. Grimes 		break;
437df8bae1dSRodney W. Grimes 
438df8bae1dSRodney W. Grimes 	case ICMP_ECHO:
4397022ea0aSGarrett Wollman 		if (!icmpbmcastecho
440d311884fSDavid Greenman 		    && (m->m_flags & (M_MCAST | M_BCAST)) != 0) {
4417022ea0aSGarrett Wollman 			icmpstat.icps_bmcastecho++;
4427022ea0aSGarrett Wollman 			break;
4437022ea0aSGarrett Wollman 		}
444df8bae1dSRodney W. Grimes 		icp->icmp_type = ICMP_ECHOREPLY;
445a57815efSBosko Milekic 		if (badport_bandlim(BANDLIM_ICMP_ECHO) < 0)
44609f81a46SBosko Milekic 			goto freeit;
44709f81a46SBosko Milekic 		else
448df8bae1dSRodney W. Grimes 			goto reflect;
449df8bae1dSRodney W. Grimes 
450df8bae1dSRodney W. Grimes 	case ICMP_TSTAMP:
451fe0fb8abSGarrett Wollman 		if (!icmpbmcastecho
452d311884fSDavid Greenman 		    && (m->m_flags & (M_MCAST | M_BCAST)) != 0) {
453fe0fb8abSGarrett Wollman 			icmpstat.icps_bmcasttstamp++;
454fe0fb8abSGarrett Wollman 			break;
455fe0fb8abSGarrett Wollman 		}
456df8bae1dSRodney W. Grimes 		if (icmplen < ICMP_TSLEN) {
457df8bae1dSRodney W. Grimes 			icmpstat.icps_badlen++;
458df8bae1dSRodney W. Grimes 			break;
459df8bae1dSRodney W. Grimes 		}
460df8bae1dSRodney W. Grimes 		icp->icmp_type = ICMP_TSTAMPREPLY;
461df8bae1dSRodney W. Grimes 		icp->icmp_rtime = iptime();
462df8bae1dSRodney W. Grimes 		icp->icmp_ttime = icp->icmp_rtime;	/* bogus, do later! */
463a57815efSBosko Milekic 		if (badport_bandlim(BANDLIM_ICMP_TSTAMP) < 0)
46409f81a46SBosko Milekic 			goto freeit;
46509f81a46SBosko Milekic 		else
466df8bae1dSRodney W. Grimes 			goto reflect;
467df8bae1dSRodney W. Grimes 
468df8bae1dSRodney W. Grimes 	case ICMP_MASKREQ:
469df8bae1dSRodney W. Grimes 		if (icmpmaskrepl == 0)
470df8bae1dSRodney W. Grimes 			break;
471df8bae1dSRodney W. Grimes 		/*
472df8bae1dSRodney W. Grimes 		 * We are not able to respond with all ones broadcast
473df8bae1dSRodney W. Grimes 		 * unless we receive it over a point-to-point interface.
474df8bae1dSRodney W. Grimes 		 */
475df8bae1dSRodney W. Grimes 		if (icmplen < ICMP_MASKLEN)
476df8bae1dSRodney W. Grimes 			break;
477df8bae1dSRodney W. Grimes 		switch (ip->ip_dst.s_addr) {
478df8bae1dSRodney W. Grimes 
479df8bae1dSRodney W. Grimes 		case INADDR_BROADCAST:
480df8bae1dSRodney W. Grimes 		case INADDR_ANY:
481df8bae1dSRodney W. Grimes 			icmpdst.sin_addr = ip->ip_src;
482df8bae1dSRodney W. Grimes 			break;
483df8bae1dSRodney W. Grimes 
484df8bae1dSRodney W. Grimes 		default:
485df8bae1dSRodney W. Grimes 			icmpdst.sin_addr = ip->ip_dst;
486df8bae1dSRodney W. Grimes 		}
487df8bae1dSRodney W. Grimes 		ia = (struct in_ifaddr *)ifaof_ifpforaddr(
488df8bae1dSRodney W. Grimes 			    (struct sockaddr *)&icmpdst, m->m_pkthdr.rcvif);
489df8bae1dSRodney W. Grimes 		if (ia == 0)
490df8bae1dSRodney W. Grimes 			break;
4917e6f7714SPoul-Henning Kamp 		if (ia->ia_ifp == 0)
4927e6f7714SPoul-Henning Kamp 			break;
493df8bae1dSRodney W. Grimes 		icp->icmp_type = ICMP_MASKREPLY;
494df8bae1dSRodney W. Grimes 		icp->icmp_mask = ia->ia_sockmask.sin_addr.s_addr;
495df8bae1dSRodney W. Grimes 		if (ip->ip_src.s_addr == 0) {
496df8bae1dSRodney W. Grimes 			if (ia->ia_ifp->if_flags & IFF_BROADCAST)
497df8bae1dSRodney W. Grimes 			    ip->ip_src = satosin(&ia->ia_broadaddr)->sin_addr;
498df8bae1dSRodney W. Grimes 			else if (ia->ia_ifp->if_flags & IFF_POINTOPOINT)
499df8bae1dSRodney W. Grimes 			    ip->ip_src = satosin(&ia->ia_dstaddr)->sin_addr;
500df8bae1dSRodney W. Grimes 		}
501df8bae1dSRodney W. Grimes reflect:
502df8bae1dSRodney W. Grimes 		ip->ip_len += hlen;	/* since ip_input deducts this */
503df8bae1dSRodney W. Grimes 		icmpstat.icps_reflect++;
504df8bae1dSRodney W. Grimes 		icmpstat.icps_outhist[icp->icmp_type]++;
505df8bae1dSRodney W. Grimes 		icmp_reflect(m);
506df8bae1dSRodney W. Grimes 		return;
507df8bae1dSRodney W. Grimes 
508df8bae1dSRodney W. Grimes 	case ICMP_REDIRECT:
50918d3153eSDag-Erling Smørgrav 		if (log_redirect) {
51018d3153eSDag-Erling Smørgrav 			u_long src, dst, gw;
51118d3153eSDag-Erling Smørgrav 
51218d3153eSDag-Erling Smørgrav 			src = ntohl(ip->ip_src.s_addr);
51318d3153eSDag-Erling Smørgrav 			dst = ntohl(icp->icmp_ip.ip_dst.s_addr);
51418d3153eSDag-Erling Smørgrav 			gw = ntohl(icp->icmp_gwaddr.s_addr);
51518d3153eSDag-Erling Smørgrav 			printf("icmp redirect from %d.%d.%d.%d: "
51618d3153eSDag-Erling Smørgrav 			       "%d.%d.%d.%d => %d.%d.%d.%d\n",
51718d3153eSDag-Erling Smørgrav 			       (int)(src >> 24), (int)((src >> 16) & 0xff),
51818d3153eSDag-Erling Smørgrav 			       (int)((src >> 8) & 0xff), (int)(src & 0xff),
51918d3153eSDag-Erling Smørgrav 			       (int)(dst >> 24), (int)((dst >> 16) & 0xff),
52018d3153eSDag-Erling Smørgrav 			       (int)((dst >> 8) & 0xff), (int)(dst & 0xff),
52118d3153eSDag-Erling Smørgrav 			       (int)(gw >> 24), (int)((gw >> 16) & 0xff),
52218d3153eSDag-Erling Smørgrav 			       (int)((gw >> 8) & 0xff), (int)(gw & 0xff));
52318d3153eSDag-Erling Smørgrav 		}
52418d3153eSDag-Erling Smørgrav 		if (drop_redirect)
52518d3153eSDag-Erling Smørgrav 			break;
526df8bae1dSRodney W. Grimes 		if (code > 3)
527df8bae1dSRodney W. Grimes 			goto badcode;
528df8bae1dSRodney W. Grimes 		if (icmplen < ICMP_ADVLENMIN || icmplen < ICMP_ADVLEN(icp) ||
5295e2d0696SGarrett Wollman 		    IP_VHL_HL(icp->icmp_ip.ip_vhl) < (sizeof(struct ip) >> 2)) {
530df8bae1dSRodney W. Grimes 			icmpstat.icps_badlen++;
531df8bae1dSRodney W. Grimes 			break;
532df8bae1dSRodney W. Grimes 		}
533df8bae1dSRodney W. Grimes 		/*
534df8bae1dSRodney W. Grimes 		 * Short circuit routing redirects to force
535df8bae1dSRodney W. Grimes 		 * immediate change in the kernel's routing
536df8bae1dSRodney W. Grimes 		 * tables.  The message is also handed to anyone
537df8bae1dSRodney W. Grimes 		 * listening on a raw socket (e.g. the routing
538df8bae1dSRodney W. Grimes 		 * daemon for use in updating its tables).
539df8bae1dSRodney W. Grimes 		 */
540df8bae1dSRodney W. Grimes 		icmpgw.sin_addr = ip->ip_src;
541df8bae1dSRodney W. Grimes 		icmpdst.sin_addr = icp->icmp_gwaddr;
542df8bae1dSRodney W. Grimes #ifdef	ICMPPRINTFS
5432b758395SGarrett Wollman 		if (icmpprintfs) {
5442b758395SGarrett Wollman 			char buf[4 * sizeof "123"];
5452b758395SGarrett Wollman 			strcpy(buf, inet_ntoa(icp->icmp_ip.ip_dst));
5462b758395SGarrett Wollman 
5472b758395SGarrett Wollman 			printf("redirect dst %s to %s\n",
5482b758395SGarrett Wollman 			       buf, inet_ntoa(icp->icmp_gwaddr));
5492b758395SGarrett Wollman 		}
550df8bae1dSRodney W. Grimes #endif
551df8bae1dSRodney W. Grimes 		icmpsrc.sin_addr = icp->icmp_ip.ip_dst;
552df8bae1dSRodney W. Grimes 		rtredirect((struct sockaddr *)&icmpsrc,
553df8bae1dSRodney W. Grimes 		  (struct sockaddr *)&icmpdst,
554df8bae1dSRodney W. Grimes 		  (struct sockaddr *)0, RTF_GATEWAY | RTF_HOST,
555df8bae1dSRodney W. Grimes 		  (struct sockaddr *)&icmpgw, (struct rtentry **)0);
556df8bae1dSRodney W. Grimes 		pfctlinput(PRC_REDIRECT_HOST, (struct sockaddr *)&icmpsrc);
5576a800098SYoshinobu Inoue #ifdef IPSEC
5586a800098SYoshinobu Inoue 		key_sa_routechange((struct sockaddr *)&icmpsrc);
5596a800098SYoshinobu Inoue #endif
560df8bae1dSRodney W. Grimes 		break;
561df8bae1dSRodney W. Grimes 
562df8bae1dSRodney W. Grimes 	/*
563df8bae1dSRodney W. Grimes 	 * No kernel processing for the following;
564df8bae1dSRodney W. Grimes 	 * just fall through to send to raw listener.
565df8bae1dSRodney W. Grimes 	 */
566df8bae1dSRodney W. Grimes 	case ICMP_ECHOREPLY:
567df8bae1dSRodney W. Grimes 	case ICMP_ROUTERADVERT:
568df8bae1dSRodney W. Grimes 	case ICMP_ROUTERSOLICIT:
569df8bae1dSRodney W. Grimes 	case ICMP_TSTAMPREPLY:
570df8bae1dSRodney W. Grimes 	case ICMP_IREQREPLY:
571df8bae1dSRodney W. Grimes 	case ICMP_MASKREPLY:
572df8bae1dSRodney W. Grimes 	default:
573df8bae1dSRodney W. Grimes 		break;
574df8bae1dSRodney W. Grimes 	}
575df8bae1dSRodney W. Grimes 
576df8bae1dSRodney W. Grimes raw:
577f0ffb944SJulian Elischer 	rip_input(m, off);
578df8bae1dSRodney W. Grimes 	return;
579df8bae1dSRodney W. Grimes 
580df8bae1dSRodney W. Grimes freeit:
581df8bae1dSRodney W. Grimes 	m_freem(m);
582df8bae1dSRodney W. Grimes }
583df8bae1dSRodney W. Grimes 
584df8bae1dSRodney W. Grimes /*
585df8bae1dSRodney W. Grimes  * Reflect the ip packet back to the source
586df8bae1dSRodney W. Grimes  */
5870312fbe9SPoul-Henning Kamp static void
588df8bae1dSRodney W. Grimes icmp_reflect(m)
589df8bae1dSRodney W. Grimes 	struct mbuf *m;
590df8bae1dSRodney W. Grimes {
591ca925d9cSJonathan Lemon 	struct ip *ip = mtod(m, struct ip *);
592ca925d9cSJonathan Lemon 	struct ifaddr *ifa;
593ca925d9cSJonathan Lemon 	struct in_ifaddr *ia;
594df8bae1dSRodney W. Grimes 	struct in_addr t;
595b5e8ce9fSBruce Evans 	struct mbuf *opts = 0;
5965e2d0696SGarrett Wollman 	int optlen = (IP_VHL_HL(ip->ip_vhl) << 2) - sizeof(struct ip);
597bd714208SRuslan Ermilov 	struct route *ro = NULL, rt;
598df8bae1dSRodney W. Grimes 
599df8bae1dSRodney W. Grimes 	if (!in_canforward(ip->ip_src) &&
600df8bae1dSRodney W. Grimes 	    ((ntohl(ip->ip_src.s_addr) & IN_CLASSA_NET) !=
601df8bae1dSRodney W. Grimes 	     (IN_LOOPBACKNET << IN_CLASSA_NSHIFT))) {
602df8bae1dSRodney W. Grimes 		m_freem(m);	/* Bad return address */
603bd714208SRuslan Ermilov 		icmpstat.icps_badaddr++;
604df8bae1dSRodney W. Grimes 		goto done;	/* Ip_output() will check for broadcast */
605df8bae1dSRodney W. Grimes 	}
606df8bae1dSRodney W. Grimes 	t = ip->ip_dst;
607df8bae1dSRodney W. Grimes 	ip->ip_dst = ip->ip_src;
608e3f406b3SRuslan Ermilov 	ro = &rt;
609e3f406b3SRuslan Ermilov 	bzero(ro, sizeof(*ro));
610df8bae1dSRodney W. Grimes 	/*
611df8bae1dSRodney W. Grimes 	 * If the incoming packet was addressed directly to us,
612df8bae1dSRodney W. Grimes 	 * use dst as the src for the reply.  Otherwise (broadcast
613df8bae1dSRodney W. Grimes 	 * or anonymous), use the address which corresponds
614df8bae1dSRodney W. Grimes 	 * to the incoming interface.
615df8bae1dSRodney W. Grimes 	 */
616ca925d9cSJonathan Lemon 	LIST_FOREACH(ia, INADDR_HASH(t.s_addr), ia_hash)
617df8bae1dSRodney W. Grimes 		if (t.s_addr == IA_SIN(ia)->sin_addr.s_addr)
618ca925d9cSJonathan Lemon 			goto match;
61984caf008SRuslan Ermilov 	if (m->m_pkthdr.rcvif != NULL &&
62084caf008SRuslan Ermilov 	    m->m_pkthdr.rcvif->if_flags & IFF_BROADCAST) {
621ca925d9cSJonathan Lemon 		TAILQ_FOREACH(ifa, &m->m_pkthdr.rcvif->if_addrhead, ifa_link) {
622ca925d9cSJonathan Lemon 			if (ifa->ifa_addr->sa_family != AF_INET)
623ca925d9cSJonathan Lemon 				continue;
624ca925d9cSJonathan Lemon 			ia = ifatoia(ifa);
625ca925d9cSJonathan Lemon 			if (satosin(&ia->ia_broadaddr)->sin_addr.s_addr ==
626ca925d9cSJonathan Lemon 			    t.s_addr)
627ca925d9cSJonathan Lemon 				goto match;
628df8bae1dSRodney W. Grimes 		}
629ca925d9cSJonathan Lemon 	}
630bd714208SRuslan Ermilov 	ia = ip_rtaddr(ip->ip_dst, ro);
631bd714208SRuslan Ermilov 	/* We need a route to do anything useful. */
6320d4bef5dSDima Dorfman 	if (ia == NULL) {
6330d4bef5dSDima Dorfman 		m_freem(m);
634bd714208SRuslan Ermilov 		icmpstat.icps_noroute++;
6350d4bef5dSDima Dorfman 		goto done;
6360d4bef5dSDima Dorfman 	}
637ca925d9cSJonathan Lemon match:
638df8bae1dSRodney W. Grimes 	t = IA_SIN(ia)->sin_addr;
639df8bae1dSRodney W. Grimes 	ip->ip_src = t;
6408ce3f3ddSRuslan Ermilov 	ip->ip_ttl = ip_defttl;
641df8bae1dSRodney W. Grimes 
642df8bae1dSRodney W. Grimes 	if (optlen > 0) {
643df8bae1dSRodney W. Grimes 		register u_char *cp;
644df8bae1dSRodney W. Grimes 		int opt, cnt;
645df8bae1dSRodney W. Grimes 		u_int len;
646df8bae1dSRodney W. Grimes 
647df8bae1dSRodney W. Grimes 		/*
648df8bae1dSRodney W. Grimes 		 * Retrieve any source routing from the incoming packet;
649df8bae1dSRodney W. Grimes 		 * add on any record-route or timestamp options.
650df8bae1dSRodney W. Grimes 		 */
651df8bae1dSRodney W. Grimes 		cp = (u_char *) (ip + 1);
652df8bae1dSRodney W. Grimes 		if ((opts = ip_srcroute()) == 0 &&
653df8bae1dSRodney W. Grimes 		    (opts = m_gethdr(M_DONTWAIT, MT_HEADER))) {
654df8bae1dSRodney W. Grimes 			opts->m_len = sizeof(struct in_addr);
655df8bae1dSRodney W. Grimes 			mtod(opts, struct in_addr *)->s_addr = 0;
656df8bae1dSRodney W. Grimes 		}
657df8bae1dSRodney W. Grimes 		if (opts) {
658df8bae1dSRodney W. Grimes #ifdef ICMPPRINTFS
659df8bae1dSRodney W. Grimes 		    if (icmpprintfs)
660df8bae1dSRodney W. Grimes 			    printf("icmp_reflect optlen %d rt %d => ",
661df8bae1dSRodney W. Grimes 				optlen, opts->m_len);
662df8bae1dSRodney W. Grimes #endif
663df8bae1dSRodney W. Grimes 		    for (cnt = optlen; cnt > 0; cnt -= len, cp += len) {
664df8bae1dSRodney W. Grimes 			    opt = cp[IPOPT_OPTVAL];
665df8bae1dSRodney W. Grimes 			    if (opt == IPOPT_EOL)
666df8bae1dSRodney W. Grimes 				    break;
667df8bae1dSRodney W. Grimes 			    if (opt == IPOPT_NOP)
668df8bae1dSRodney W. Grimes 				    len = 1;
669df8bae1dSRodney W. Grimes 			    else {
670707d00a3SJonathan Lemon 				    if (cnt < IPOPT_OLEN + sizeof(*cp))
671707d00a3SJonathan Lemon 					    break;
672df8bae1dSRodney W. Grimes 				    len = cp[IPOPT_OLEN];
673707d00a3SJonathan Lemon 				    if (len < IPOPT_OLEN + sizeof(*cp) ||
674707d00a3SJonathan Lemon 				        len > cnt)
675df8bae1dSRodney W. Grimes 					    break;
676df8bae1dSRodney W. Grimes 			    }
677df8bae1dSRodney W. Grimes 			    /*
678df8bae1dSRodney W. Grimes 			     * Should check for overflow, but it "can't happen"
679df8bae1dSRodney W. Grimes 			     */
680df8bae1dSRodney W. Grimes 			    if (opt == IPOPT_RR || opt == IPOPT_TS ||
681df8bae1dSRodney W. Grimes 				opt == IPOPT_SECURITY) {
682df8bae1dSRodney W. Grimes 				    bcopy((caddr_t)cp,
683df8bae1dSRodney W. Grimes 					mtod(opts, caddr_t) + opts->m_len, len);
684df8bae1dSRodney W. Grimes 				    opts->m_len += len;
685df8bae1dSRodney W. Grimes 			    }
686df8bae1dSRodney W. Grimes 		    }
687df8bae1dSRodney W. Grimes 		    /* Terminate & pad, if necessary */
688623ae52eSPoul-Henning Kamp 		    cnt = opts->m_len % 4;
689623ae52eSPoul-Henning Kamp 		    if (cnt) {
690df8bae1dSRodney W. Grimes 			    for (; cnt < 4; cnt++) {
691df8bae1dSRodney W. Grimes 				    *(mtod(opts, caddr_t) + opts->m_len) =
692df8bae1dSRodney W. Grimes 					IPOPT_EOL;
693df8bae1dSRodney W. Grimes 				    opts->m_len++;
694df8bae1dSRodney W. Grimes 			    }
695df8bae1dSRodney W. Grimes 		    }
696df8bae1dSRodney W. Grimes #ifdef ICMPPRINTFS
697df8bae1dSRodney W. Grimes 		    if (icmpprintfs)
698df8bae1dSRodney W. Grimes 			    printf("%d\n", opts->m_len);
699df8bae1dSRodney W. Grimes #endif
700df8bae1dSRodney W. Grimes 		}
701df8bae1dSRodney W. Grimes 		/*
702df8bae1dSRodney W. Grimes 		 * Now strip out original options by copying rest of first
703df8bae1dSRodney W. Grimes 		 * mbuf's data back, and adjust the IP length.
704df8bae1dSRodney W. Grimes 		 */
705df8bae1dSRodney W. Grimes 		ip->ip_len -= optlen;
7065e2d0696SGarrett Wollman 		ip->ip_vhl = IP_VHL_BORING;
707df8bae1dSRodney W. Grimes 		m->m_len -= optlen;
708df8bae1dSRodney W. Grimes 		if (m->m_flags & M_PKTHDR)
709df8bae1dSRodney W. Grimes 			m->m_pkthdr.len -= optlen;
710df8bae1dSRodney W. Grimes 		optlen += sizeof(struct ip);
711df8bae1dSRodney W. Grimes 		bcopy((caddr_t)ip + optlen, (caddr_t)(ip + 1),
712df8bae1dSRodney W. Grimes 			 (unsigned)(m->m_len - sizeof(struct ip)));
713df8bae1dSRodney W. Grimes 	}
714df8bae1dSRodney W. Grimes 	m->m_flags &= ~(M_BCAST|M_MCAST);
715bd714208SRuslan Ermilov 	icmp_send(m, opts, ro);
716df8bae1dSRodney W. Grimes done:
717df8bae1dSRodney W. Grimes 	if (opts)
718df8bae1dSRodney W. Grimes 		(void)m_free(opts);
719bd714208SRuslan Ermilov 	if (ro && ro->ro_rt)
720bd714208SRuslan Ermilov 		RTFREE(ro->ro_rt);
721df8bae1dSRodney W. Grimes }
722df8bae1dSRodney W. Grimes 
723df8bae1dSRodney W. Grimes /*
724df8bae1dSRodney W. Grimes  * Send an icmp packet back to the ip level,
725df8bae1dSRodney W. Grimes  * after supplying a checksum.
726df8bae1dSRodney W. Grimes  */
7270312fbe9SPoul-Henning Kamp static void
728bd714208SRuslan Ermilov icmp_send(m, opts, rt)
729df8bae1dSRodney W. Grimes 	register struct mbuf *m;
730df8bae1dSRodney W. Grimes 	struct mbuf *opts;
731bd714208SRuslan Ermilov 	struct route *rt;
732df8bae1dSRodney W. Grimes {
733df8bae1dSRodney W. Grimes 	register struct ip *ip = mtod(m, struct ip *);
734df8bae1dSRodney W. Grimes 	register int hlen;
735df8bae1dSRodney W. Grimes 	register struct icmp *icp;
736df8bae1dSRodney W. Grimes 
7375e2d0696SGarrett Wollman 	hlen = IP_VHL_HL(ip->ip_vhl) << 2;
738df8bae1dSRodney W. Grimes 	m->m_data += hlen;
739df8bae1dSRodney W. Grimes 	m->m_len -= hlen;
740df8bae1dSRodney W. Grimes 	icp = mtod(m, struct icmp *);
741df8bae1dSRodney W. Grimes 	icp->icmp_cksum = 0;
742df8bae1dSRodney W. Grimes 	icp->icmp_cksum = in_cksum(m, ip->ip_len - hlen);
743df8bae1dSRodney W. Grimes 	m->m_data -= hlen;
744df8bae1dSRodney W. Grimes 	m->m_len += hlen;
74594446a2eSArchie Cobbs 	m->m_pkthdr.rcvif = (struct ifnet *)0;
746df8bae1dSRodney W. Grimes #ifdef ICMPPRINTFS
7472b758395SGarrett Wollman 	if (icmpprintfs) {
7482b758395SGarrett Wollman 		char buf[4 * sizeof "123"];
7492b758395SGarrett Wollman 		strcpy(buf, inet_ntoa(ip->ip_dst));
7502b758395SGarrett Wollman 		printf("icmp_send dst %s src %s\n",
7512b758395SGarrett Wollman 		       buf, inet_ntoa(ip->ip_src));
7522b758395SGarrett Wollman 	}
753df8bae1dSRodney W. Grimes #endif
754bd714208SRuslan Ermilov 	(void) ip_output(m, opts, rt, 0, NULL);
755df8bae1dSRodney W. Grimes }
756df8bae1dSRodney W. Grimes 
757df8bae1dSRodney W. Grimes n_time
758df8bae1dSRodney W. Grimes iptime()
759df8bae1dSRodney W. Grimes {
760df8bae1dSRodney W. Grimes 	struct timeval atv;
761df8bae1dSRodney W. Grimes 	u_long t;
762df8bae1dSRodney W. Grimes 
76316cd6db0SBill Fumerola 	getmicrotime(&atv);
764df8bae1dSRodney W. Grimes 	t = (atv.tv_sec % (24*60*60)) * 1000 + atv.tv_usec / 1000;
765df8bae1dSRodney W. Grimes 	return (htonl(t));
766df8bae1dSRodney W. Grimes }
767df8bae1dSRodney W. Grimes 
768b7a44e34SGarrett Wollman #if 1
7695cbf3e08SGarrett Wollman /*
7705cbf3e08SGarrett Wollman  * Return the next larger or smaller MTU plateau (table from RFC 1191)
7715cbf3e08SGarrett Wollman  * given current value MTU.  If DIR is less than zero, a larger plateau
7725cbf3e08SGarrett Wollman  * is returned; otherwise, a smaller value is returned.
7735cbf3e08SGarrett Wollman  */
774f708ef1bSPoul-Henning Kamp static int
7755cbf3e08SGarrett Wollman ip_next_mtu(mtu, dir)
7765cbf3e08SGarrett Wollman 	int mtu;
7775cbf3e08SGarrett Wollman 	int dir;
7785cbf3e08SGarrett Wollman {
7795cbf3e08SGarrett Wollman 	static int mtutab[] = {
7805cbf3e08SGarrett Wollman 		65535, 32000, 17914, 8166, 4352, 2002, 1492, 1006, 508, 296,
7815cbf3e08SGarrett Wollman 		68, 0
7825cbf3e08SGarrett Wollman 	};
7835cbf3e08SGarrett Wollman 	int i;
7845cbf3e08SGarrett Wollman 
7855cbf3e08SGarrett Wollman 	for (i = 0; i < (sizeof mtutab) / (sizeof mtutab[0]); i++) {
7865cbf3e08SGarrett Wollman 		if (mtu >= mtutab[i])
7875cbf3e08SGarrett Wollman 			break;
7885cbf3e08SGarrett Wollman 	}
7895cbf3e08SGarrett Wollman 
7905cbf3e08SGarrett Wollman 	if (dir < 0) {
7915cbf3e08SGarrett Wollman 		if (i == 0) {
7925cbf3e08SGarrett Wollman 			return 0;
7935cbf3e08SGarrett Wollman 		} else {
7945cbf3e08SGarrett Wollman 			return mtutab[i - 1];
7955cbf3e08SGarrett Wollman 		}
7965cbf3e08SGarrett Wollman 	} else {
7975cbf3e08SGarrett Wollman 		if (mtutab[i] == 0) {
7985cbf3e08SGarrett Wollman 			return 0;
7995cbf3e08SGarrett Wollman 		} else if(mtu > mtutab[i]) {
8005cbf3e08SGarrett Wollman 			return mtutab[i];
8015cbf3e08SGarrett Wollman 		} else {
8025cbf3e08SGarrett Wollman 			return mtutab[i + 1];
8035cbf3e08SGarrett Wollman 		}
8045cbf3e08SGarrett Wollman 	}
8055cbf3e08SGarrett Wollman }
806b7a44e34SGarrett Wollman #endif
80751508de1SMatthew Dillon 
80851508de1SMatthew Dillon 
80951508de1SMatthew Dillon /*
81051508de1SMatthew Dillon  * badport_bandlim() - check for ICMP bandwidth limit
81151508de1SMatthew Dillon  *
81251508de1SMatthew Dillon  *	Return 0 if it is ok to send an ICMP error response, -1 if we have
81351508de1SMatthew Dillon  *	hit our bandwidth limit and it is not ok.
81451508de1SMatthew Dillon  *
81551508de1SMatthew Dillon  *	If icmplim is <= 0, the feature is disabled and 0 is returned.
81651508de1SMatthew Dillon  *
81751508de1SMatthew Dillon  *	For now we separate the TCP and UDP subsystems w/ different 'which'
81851508de1SMatthew Dillon  *	values.  We may eventually remove this separation (and simplify the
81951508de1SMatthew Dillon  *	code further).
82051508de1SMatthew Dillon  *
82151508de1SMatthew Dillon  *	Note that the printing of the error message is delayed so we can
82251508de1SMatthew Dillon  *	properly print the icmp error rate that the system was trying to do
82351508de1SMatthew Dillon  *	(i.e. 22000/100 pps, etc...).  This can cause long delays in printing
82451508de1SMatthew Dillon  *	the 'final' error, but it doesn't make sense to solve the printing
82551508de1SMatthew Dillon  *	delay with more complex code.
82651508de1SMatthew Dillon  */
82751508de1SMatthew Dillon 
82851508de1SMatthew Dillon int
82951508de1SMatthew Dillon badport_bandlim(int which)
83051508de1SMatthew Dillon {
83109f81a46SBosko Milekic 	static int lticks[BANDLIM_MAX + 1];
83209f81a46SBosko Milekic 	static int lpackets[BANDLIM_MAX + 1];
83351508de1SMatthew Dillon 	int dticks;
83409f81a46SBosko Milekic 	const char *bandlimittype[] = {
83509f81a46SBosko Milekic 		"Limiting icmp unreach response",
83609f81a46SBosko Milekic 		"Limiting icmp ping response",
837a57815efSBosko Milekic 		"Limiting icmp tstamp response",
838a57815efSBosko Milekic 		"Limiting closed port RST response",
839a57815efSBosko Milekic 		"Limiting open port RST response"
84009f81a46SBosko Milekic 		};
84151508de1SMatthew Dillon 
84251508de1SMatthew Dillon 	/*
84351508de1SMatthew Dillon 	 * Return ok status if feature disabled or argument out of
84451508de1SMatthew Dillon 	 * ranage.
84551508de1SMatthew Dillon 	 */
84651508de1SMatthew Dillon 
84709f81a46SBosko Milekic 	if (icmplim <= 0 || which > BANDLIM_MAX || which < 0)
84851508de1SMatthew Dillon 		return(0);
84951508de1SMatthew Dillon 	dticks = ticks - lticks[which];
85051508de1SMatthew Dillon 
85151508de1SMatthew Dillon 	/*
85251508de1SMatthew Dillon 	 * reset stats when cumulative dt exceeds one second.
85351508de1SMatthew Dillon 	 */
85451508de1SMatthew Dillon 
85551508de1SMatthew Dillon 	if ((unsigned int)dticks > hz) {
8564f14ee00SDan Moschuk 		if (lpackets[which] > icmplim && icmplim_output) {
85709f81a46SBosko Milekic 			printf("%s from %d to %d packets per second\n",
85809f81a46SBosko Milekic 				bandlimittype[which],
85951508de1SMatthew Dillon 				lpackets[which],
86051508de1SMatthew Dillon 				icmplim
86151508de1SMatthew Dillon 			);
86251508de1SMatthew Dillon 		}
86351508de1SMatthew Dillon 		lticks[which] = ticks;
86451508de1SMatthew Dillon 		lpackets[which] = 0;
86551508de1SMatthew Dillon 	}
86651508de1SMatthew Dillon 
86751508de1SMatthew Dillon 	/*
86851508de1SMatthew Dillon 	 * bump packet count
86951508de1SMatthew Dillon 	 */
87051508de1SMatthew Dillon 
87151508de1SMatthew Dillon 	if (++lpackets[which] > icmplim) {
87251508de1SMatthew Dillon 		return(-1);
87351508de1SMatthew Dillon 	}
87451508de1SMatthew Dillon 	return(0);
87551508de1SMatthew Dillon }
87651508de1SMatthew Dillon 
877