xref: /freebsd/sys/netinet/ip_icmp.c (revision 7022ea0a0cff055a8ef41f0c0ae6d73a95b37735)
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
347022ea0aSGarrett Wollman  * $Id: ip_icmp.c,v 1.27 1997/08/02 14:32:53 bde Exp $
35df8bae1dSRodney W. Grimes  */
36df8bae1dSRodney W. Grimes 
37df8bae1dSRodney W. Grimes #include <sys/param.h>
38df8bae1dSRodney W. Grimes #include <sys/systm.h>
39df8bae1dSRodney W. Grimes #include <sys/mbuf.h>
40df8bae1dSRodney W. Grimes #include <sys/protosw.h>
41df8bae1dSRodney W. Grimes #include <sys/socket.h>
42df8bae1dSRodney W. Grimes #include <sys/time.h>
43df8bae1dSRodney W. Grimes #include <sys/kernel.h>
44b5e8ce9fSBruce Evans #include <sys/sysctl.h>
45df8bae1dSRodney W. Grimes 
46df8bae1dSRodney W. Grimes #include <net/if.h>
47df8bae1dSRodney W. Grimes #include <net/route.h>
48df8bae1dSRodney W. Grimes 
495e2d0696SGarrett Wollman #define _IP_VHL
50df8bae1dSRodney W. Grimes #include <netinet/in.h>
51df8bae1dSRodney W. Grimes #include <netinet/in_systm.h>
52df8bae1dSRodney W. Grimes #include <netinet/in_var.h>
53df8bae1dSRodney W. Grimes #include <netinet/ip.h>
54df8bae1dSRodney W. Grimes #include <netinet/ip_icmp.h>
55b5e8ce9fSBruce Evans #include <netinet/ip_var.h>
56df8bae1dSRodney W. Grimes #include <netinet/icmp_var.h>
57df8bae1dSRodney W. Grimes 
58df8bae1dSRodney W. Grimes /*
59df8bae1dSRodney W. Grimes  * ICMP routines: error generation, receive packet processing, and
60df8bae1dSRodney W. Grimes  * routines to turnaround packets back to the originator, and
61df8bae1dSRodney W. Grimes  * host table maintenance routines.
62df8bae1dSRodney W. Grimes  */
63df8bae1dSRodney W. Grimes 
64f708ef1bSPoul-Henning Kamp static struct	icmpstat icmpstat;
650312fbe9SPoul-Henning Kamp SYSCTL_STRUCT(_net_inet_icmp, ICMPCTL_STATS, stats, CTLFLAG_RD,
660312fbe9SPoul-Henning Kamp 	&icmpstat, icmpstat, "");
670312fbe9SPoul-Henning Kamp 
680312fbe9SPoul-Henning Kamp static int	icmpmaskrepl = 0;
690312fbe9SPoul-Henning Kamp SYSCTL_INT(_net_inet_icmp, ICMPCTL_MASKREPL, maskrepl, CTLFLAG_RW,
700312fbe9SPoul-Henning Kamp 	&icmpmaskrepl, 0, "");
710312fbe9SPoul-Henning Kamp 
727022ea0aSGarrett Wollman static int	icmpbmcastecho = 1;
737022ea0aSGarrett Wollman SYSCTL_INT(_net_inet_icmp, OID_AUTO, bmcastecho, CTLFLAG_RW, &icmpbmcastecho,
747022ea0aSGarrett Wollman 	   0, "");
757022ea0aSGarrett Wollman 
76df8bae1dSRodney W. Grimes #ifdef ICMPPRINTFS
77df8bae1dSRodney W. Grimes int	icmpprintfs = 0;
78df8bae1dSRodney W. Grimes #endif
79df8bae1dSRodney W. Grimes 
800312fbe9SPoul-Henning Kamp static void	icmp_reflect __P((struct mbuf *));
810312fbe9SPoul-Henning Kamp static void	icmp_send __P((struct mbuf *, struct mbuf *));
82f708ef1bSPoul-Henning Kamp static int	ip_next_mtu __P((int, int));
830312fbe9SPoul-Henning Kamp 
84df8bae1dSRodney W. Grimes extern	struct protosw inetsw[];
85df8bae1dSRodney W. Grimes 
86df8bae1dSRodney W. Grimes /*
87df8bae1dSRodney W. Grimes  * Generate an error packet of type error
88df8bae1dSRodney W. Grimes  * in response to bad packet ip.
89df8bae1dSRodney W. Grimes  */
90df8bae1dSRodney W. Grimes void
91df8bae1dSRodney W. Grimes icmp_error(n, type, code, dest, destifp)
92df8bae1dSRodney W. Grimes 	struct mbuf *n;
93df8bae1dSRodney W. Grimes 	int type, code;
94df8bae1dSRodney W. Grimes 	n_long dest;
95df8bae1dSRodney W. Grimes 	struct ifnet *destifp;
96df8bae1dSRodney W. Grimes {
97df8bae1dSRodney W. Grimes 	register struct ip *oip = mtod(n, struct ip *), *nip;
985e2d0696SGarrett Wollman 	register unsigned oiplen = IP_VHL_HL(oip->ip_vhl) << 2;
99df8bae1dSRodney W. Grimes 	register struct icmp *icp;
100df8bae1dSRodney W. Grimes 	register struct mbuf *m;
101df8bae1dSRodney W. Grimes 	unsigned icmplen;
102df8bae1dSRodney W. Grimes 
103df8bae1dSRodney W. Grimes #ifdef ICMPPRINTFS
104df8bae1dSRodney W. Grimes 	if (icmpprintfs)
105623ae52eSPoul-Henning Kamp 		printf("icmp_error(%p, %x, %d)\n", oip, type, code);
106df8bae1dSRodney W. Grimes #endif
107df8bae1dSRodney W. Grimes 	if (type != ICMP_REDIRECT)
108df8bae1dSRodney W. Grimes 		icmpstat.icps_error++;
109df8bae1dSRodney W. Grimes 	/*
110df8bae1dSRodney W. Grimes 	 * Don't send error if not the first fragment of message.
111df8bae1dSRodney W. Grimes 	 * Don't error if the old packet protocol was ICMP
112df8bae1dSRodney W. Grimes 	 * error message, only known informational types.
113df8bae1dSRodney W. Grimes 	 */
114df8bae1dSRodney W. Grimes 	if (oip->ip_off &~ (IP_MF|IP_DF))
115df8bae1dSRodney W. Grimes 		goto freeit;
116df8bae1dSRodney W. Grimes 	if (oip->ip_p == IPPROTO_ICMP && type != ICMP_REDIRECT &&
117df8bae1dSRodney W. Grimes 	  n->m_len >= oiplen + ICMP_MINLEN &&
118df8bae1dSRodney W. Grimes 	  !ICMP_INFOTYPE(((struct icmp *)((caddr_t)oip + oiplen))->icmp_type)) {
119df8bae1dSRodney W. Grimes 		icmpstat.icps_oldicmp++;
120df8bae1dSRodney W. Grimes 		goto freeit;
121df8bae1dSRodney W. Grimes 	}
122df8bae1dSRodney W. Grimes 	/* Don't send error in response to a multicast or broadcast packet */
123df8bae1dSRodney W. Grimes 	if (n->m_flags & (M_BCAST|M_MCAST))
124df8bae1dSRodney W. Grimes 		goto freeit;
125df8bae1dSRodney W. Grimes 	/*
126df8bae1dSRodney W. Grimes 	 * First, formulate icmp message
127df8bae1dSRodney W. Grimes 	 */
128df8bae1dSRodney W. Grimes 	m = m_gethdr(M_DONTWAIT, MT_HEADER);
129df8bae1dSRodney W. Grimes 	if (m == NULL)
130df8bae1dSRodney W. Grimes 		goto freeit;
131df8bae1dSRodney W. Grimes 	icmplen = oiplen + min(8, oip->ip_len);
132df8bae1dSRodney W. Grimes 	m->m_len = icmplen + ICMP_MINLEN;
133df8bae1dSRodney W. Grimes 	MH_ALIGN(m, m->m_len);
134df8bae1dSRodney W. Grimes 	icp = mtod(m, struct icmp *);
135df8bae1dSRodney W. Grimes 	if ((u_int)type > ICMP_MAXTYPE)
136df8bae1dSRodney W. Grimes 		panic("icmp_error");
137df8bae1dSRodney W. Grimes 	icmpstat.icps_outhist[type]++;
138df8bae1dSRodney W. Grimes 	icp->icmp_type = type;
139df8bae1dSRodney W. Grimes 	if (type == ICMP_REDIRECT)
140df8bae1dSRodney W. Grimes 		icp->icmp_gwaddr.s_addr = dest;
141df8bae1dSRodney W. Grimes 	else {
142df8bae1dSRodney W. Grimes 		icp->icmp_void = 0;
143df8bae1dSRodney W. Grimes 		/*
144df8bae1dSRodney W. Grimes 		 * The following assignments assume an overlay with the
145df8bae1dSRodney W. Grimes 		 * zeroed icmp_void field.
146df8bae1dSRodney W. Grimes 		 */
147df8bae1dSRodney W. Grimes 		if (type == ICMP_PARAMPROB) {
148df8bae1dSRodney W. Grimes 			icp->icmp_pptr = code;
149df8bae1dSRodney W. Grimes 			code = 0;
150df8bae1dSRodney W. Grimes 		} else if (type == ICMP_UNREACH &&
151df8bae1dSRodney W. Grimes 			code == ICMP_UNREACH_NEEDFRAG && destifp) {
152df8bae1dSRodney W. Grimes 			icp->icmp_nextmtu = htons(destifp->if_mtu);
153df8bae1dSRodney W. Grimes 		}
154df8bae1dSRodney W. Grimes 	}
155df8bae1dSRodney W. Grimes 
156df8bae1dSRodney W. Grimes 	icp->icmp_code = code;
157df8bae1dSRodney W. Grimes 	bcopy((caddr_t)oip, (caddr_t)&icp->icmp_ip, icmplen);
158df8bae1dSRodney W. Grimes 	nip = &icp->icmp_ip;
159df8bae1dSRodney W. Grimes 	nip->ip_len = htons((u_short)(nip->ip_len + oiplen));
160df8bae1dSRodney W. Grimes 
161df8bae1dSRodney W. Grimes 	/*
162df8bae1dSRodney W. Grimes 	 * Now, copy old ip header (without options)
163df8bae1dSRodney W. Grimes 	 * in front of icmp message.
164df8bae1dSRodney W. Grimes 	 */
165df8bae1dSRodney W. Grimes 	if (m->m_data - sizeof(struct ip) < m->m_pktdat)
166df8bae1dSRodney W. Grimes 		panic("icmp len");
167df8bae1dSRodney W. Grimes 	m->m_data -= sizeof(struct ip);
168df8bae1dSRodney W. Grimes 	m->m_len += sizeof(struct ip);
169df8bae1dSRodney W. Grimes 	m->m_pkthdr.len = m->m_len;
170df8bae1dSRodney W. Grimes 	m->m_pkthdr.rcvif = n->m_pkthdr.rcvif;
171df8bae1dSRodney W. Grimes 	nip = mtod(m, struct ip *);
172df8bae1dSRodney W. Grimes 	bcopy((caddr_t)oip, (caddr_t)nip, sizeof(struct ip));
173df8bae1dSRodney W. Grimes 	nip->ip_len = m->m_len;
1745e2d0696SGarrett Wollman 	nip->ip_vhl = IP_VHL_BORING;
175df8bae1dSRodney W. Grimes 	nip->ip_p = IPPROTO_ICMP;
176df8bae1dSRodney W. Grimes 	nip->ip_tos = 0;
177df8bae1dSRodney W. Grimes 	icmp_reflect(m);
178df8bae1dSRodney W. Grimes 
179df8bae1dSRodney W. Grimes freeit:
180df8bae1dSRodney W. Grimes 	m_freem(n);
181df8bae1dSRodney W. Grimes }
182df8bae1dSRodney W. Grimes 
183df8bae1dSRodney W. Grimes static struct sockaddr_in icmpsrc = { sizeof (struct sockaddr_in), AF_INET };
184df8bae1dSRodney W. Grimes static struct sockaddr_in icmpdst = { sizeof (struct sockaddr_in), AF_INET };
185df8bae1dSRodney W. Grimes static struct sockaddr_in icmpgw = { sizeof (struct sockaddr_in), AF_INET };
186df8bae1dSRodney W. Grimes 
187df8bae1dSRodney W. Grimes /*
188df8bae1dSRodney W. Grimes  * Process a received ICMP message.
189df8bae1dSRodney W. Grimes  */
190df8bae1dSRodney W. Grimes void
191df8bae1dSRodney W. Grimes icmp_input(m, hlen)
192df8bae1dSRodney W. Grimes 	register struct mbuf *m;
193df8bae1dSRodney W. Grimes 	int hlen;
194df8bae1dSRodney W. Grimes {
195df8bae1dSRodney W. Grimes 	register struct icmp *icp;
196df8bae1dSRodney W. Grimes 	register struct ip *ip = mtod(m, struct ip *);
197df8bae1dSRodney W. Grimes 	int icmplen = ip->ip_len;
198df8bae1dSRodney W. Grimes 	register int i;
199df8bae1dSRodney W. Grimes 	struct in_ifaddr *ia;
200b62d102cSBruce Evans 	void (*ctlfunc) __P((int, struct sockaddr *, void *));
201df8bae1dSRodney W. Grimes 	int code;
202df8bae1dSRodney W. Grimes 
203df8bae1dSRodney W. Grimes 	/*
204df8bae1dSRodney W. Grimes 	 * Locate icmp structure in mbuf, and check
205df8bae1dSRodney W. Grimes 	 * that not corrupted and of at least minimum length.
206df8bae1dSRodney W. Grimes 	 */
207df8bae1dSRodney W. Grimes #ifdef ICMPPRINTFS
2082b758395SGarrett Wollman 	if (icmpprintfs) {
2092b758395SGarrett Wollman 		char buf[4 * sizeof "123"];
2102b758395SGarrett Wollman 		strcpy(buf, inet_ntoa(ip->ip_src));
2112b758395SGarrett Wollman 		printf("icmp_input from %s to %s, len %d\n",
2122b758395SGarrett Wollman 		       buf, inet_ntoa(ip->ip_dst), icmplen);
2132b758395SGarrett Wollman 	}
214df8bae1dSRodney W. Grimes #endif
215df8bae1dSRodney W. Grimes 	if (icmplen < ICMP_MINLEN) {
216df8bae1dSRodney W. Grimes 		icmpstat.icps_tooshort++;
217df8bae1dSRodney W. Grimes 		goto freeit;
218df8bae1dSRodney W. Grimes 	}
219df8bae1dSRodney W. Grimes 	i = hlen + min(icmplen, ICMP_ADVLENMIN);
220df8bae1dSRodney W. Grimes 	if (m->m_len < i && (m = m_pullup(m, i)) == 0)  {
221df8bae1dSRodney W. Grimes 		icmpstat.icps_tooshort++;
222df8bae1dSRodney W. Grimes 		return;
223df8bae1dSRodney W. Grimes 	}
224df8bae1dSRodney W. Grimes 	ip = mtod(m, struct ip *);
225df8bae1dSRodney W. Grimes 	m->m_len -= hlen;
226df8bae1dSRodney W. Grimes 	m->m_data += hlen;
227df8bae1dSRodney W. Grimes 	icp = mtod(m, struct icmp *);
228df8bae1dSRodney W. Grimes 	if (in_cksum(m, icmplen)) {
229df8bae1dSRodney W. Grimes 		icmpstat.icps_checksum++;
230df8bae1dSRodney W. Grimes 		goto freeit;
231df8bae1dSRodney W. Grimes 	}
232df8bae1dSRodney W. Grimes 	m->m_len += hlen;
233df8bae1dSRodney W. Grimes 	m->m_data -= hlen;
234df8bae1dSRodney W. Grimes 
235df8bae1dSRodney W. Grimes #ifdef ICMPPRINTFS
236df8bae1dSRodney W. Grimes 	if (icmpprintfs)
237df8bae1dSRodney W. Grimes 		printf("icmp_input, type %d code %d\n", icp->icmp_type,
238df8bae1dSRodney W. Grimes 		    icp->icmp_code);
239df8bae1dSRodney W. Grimes #endif
2405b7ee6edSGarrett Wollman 
2415b7ee6edSGarrett Wollman 	/*
2425b7ee6edSGarrett Wollman 	 * Message type specific processing.
2435b7ee6edSGarrett Wollman 	 */
244df8bae1dSRodney W. Grimes 	if (icp->icmp_type > ICMP_MAXTYPE)
245df8bae1dSRodney W. Grimes 		goto raw;
246df8bae1dSRodney W. Grimes 	icmpstat.icps_inhist[icp->icmp_type]++;
247df8bae1dSRodney W. Grimes 	code = icp->icmp_code;
248df8bae1dSRodney W. Grimes 	switch (icp->icmp_type) {
249df8bae1dSRodney W. Grimes 
250df8bae1dSRodney W. Grimes 	case ICMP_UNREACH:
251df8bae1dSRodney W. Grimes 		switch (code) {
252df8bae1dSRodney W. Grimes 			case ICMP_UNREACH_NET:
253df8bae1dSRodney W. Grimes 			case ICMP_UNREACH_HOST:
254df8bae1dSRodney W. Grimes 			case ICMP_UNREACH_PROTOCOL:
255df8bae1dSRodney W. Grimes 			case ICMP_UNREACH_PORT:
256df8bae1dSRodney W. Grimes 			case ICMP_UNREACH_SRCFAIL:
257df8bae1dSRodney W. Grimes 				code += PRC_UNREACH_NET;
258df8bae1dSRodney W. Grimes 				break;
259df8bae1dSRodney W. Grimes 
260df8bae1dSRodney W. Grimes 			case ICMP_UNREACH_NEEDFRAG:
261df8bae1dSRodney W. Grimes 				code = PRC_MSGSIZE;
262df8bae1dSRodney W. Grimes 				break;
263df8bae1dSRodney W. Grimes 
264df8bae1dSRodney W. Grimes 			case ICMP_UNREACH_NET_UNKNOWN:
265df8bae1dSRodney W. Grimes 			case ICMP_UNREACH_NET_PROHIB:
266df8bae1dSRodney W. Grimes 			case ICMP_UNREACH_TOSNET:
267df8bae1dSRodney W. Grimes 				code = PRC_UNREACH_NET;
268df8bae1dSRodney W. Grimes 				break;
269df8bae1dSRodney W. Grimes 
270df8bae1dSRodney W. Grimes 			case ICMP_UNREACH_HOST_UNKNOWN:
271df8bae1dSRodney W. Grimes 			case ICMP_UNREACH_ISOLATED:
272df8bae1dSRodney W. Grimes 			case ICMP_UNREACH_HOST_PROHIB:
273df8bae1dSRodney W. Grimes 			case ICMP_UNREACH_TOSHOST:
274df8bae1dSRodney W. Grimes 				code = PRC_UNREACH_HOST;
275df8bae1dSRodney W. Grimes 				break;
276df8bae1dSRodney W. Grimes 
2779c4b2574SPaul Traina 			case ICMP_UNREACH_FILTER_PROHIB:
2789c4b2574SPaul Traina 			case ICMP_UNREACH_HOST_PRECEDENCE:
2799c4b2574SPaul Traina 			case ICMP_UNREACH_PRECEDENCE_CUTOFF:
2809c4b2574SPaul Traina 				code = PRC_UNREACH_PORT;
2819c4b2574SPaul Traina 				break;
2829c4b2574SPaul Traina 
283df8bae1dSRodney W. Grimes 			default:
284df8bae1dSRodney W. Grimes 				goto badcode;
285df8bae1dSRodney W. Grimes 		}
286df8bae1dSRodney W. Grimes 		goto deliver;
287df8bae1dSRodney W. Grimes 
288df8bae1dSRodney W. Grimes 	case ICMP_TIMXCEED:
289df8bae1dSRodney W. Grimes 		if (code > 1)
290df8bae1dSRodney W. Grimes 			goto badcode;
291df8bae1dSRodney W. Grimes 		code += PRC_TIMXCEED_INTRANS;
292df8bae1dSRodney W. Grimes 		goto deliver;
293df8bae1dSRodney W. Grimes 
294df8bae1dSRodney W. Grimes 	case ICMP_PARAMPROB:
295df8bae1dSRodney W. Grimes 		if (code > 1)
296df8bae1dSRodney W. Grimes 			goto badcode;
297df8bae1dSRodney W. Grimes 		code = PRC_PARAMPROB;
298df8bae1dSRodney W. Grimes 		goto deliver;
299df8bae1dSRodney W. Grimes 
300df8bae1dSRodney W. Grimes 	case ICMP_SOURCEQUENCH:
301df8bae1dSRodney W. Grimes 		if (code)
302df8bae1dSRodney W. Grimes 			goto badcode;
303df8bae1dSRodney W. Grimes 		code = PRC_QUENCH;
304df8bae1dSRodney W. Grimes 	deliver:
305df8bae1dSRodney W. Grimes 		/*
306df8bae1dSRodney W. Grimes 		 * Problem with datagram; advise higher level routines.
307df8bae1dSRodney W. Grimes 		 */
308df8bae1dSRodney W. Grimes 		if (icmplen < ICMP_ADVLENMIN || icmplen < ICMP_ADVLEN(icp) ||
3095e2d0696SGarrett Wollman 		    IP_VHL_HL(icp->icmp_ip.ip_vhl) < (sizeof(struct ip) >> 2)) {
310df8bae1dSRodney W. Grimes 			icmpstat.icps_badlen++;
311df8bae1dSRodney W. Grimes 			goto freeit;
312df8bae1dSRodney W. Grimes 		}
313df8bae1dSRodney W. Grimes 		NTOHS(icp->icmp_ip.ip_len);
3145b7ee6edSGarrett Wollman 		/* Discard ICMP's in response to multicast packets */
3155b7ee6edSGarrett Wollman 		if (IN_MULTICAST(ntohl(icp->icmp_ip.ip_dst.s_addr)))
3165b7ee6edSGarrett Wollman 			goto badcode;
317df8bae1dSRodney W. Grimes #ifdef ICMPPRINTFS
318df8bae1dSRodney W. Grimes 		if (icmpprintfs)
319df8bae1dSRodney W. Grimes 			printf("deliver to protocol %d\n", icp->icmp_ip.ip_p);
320df8bae1dSRodney W. Grimes #endif
321df8bae1dSRodney W. Grimes 		icmpsrc.sin_addr = icp->icmp_ip.ip_dst;
322b7a44e34SGarrett Wollman #if 1
3235cbf3e08SGarrett Wollman 		/*
3245cbf3e08SGarrett Wollman 		 * MTU discovery:
3255cbf3e08SGarrett Wollman 		 * If we got a needfrag and there is a host route to the
3265cbf3e08SGarrett Wollman 		 * original destination, and the MTU is not locked, then
3275cbf3e08SGarrett Wollman 		 * set the MTU in the route to the suggested new value
3285cbf3e08SGarrett Wollman 		 * (if given) and then notify as usual.  The ULPs will
3295cbf3e08SGarrett Wollman 		 * notice that the MTU has changed and adapt accordingly.
3305cbf3e08SGarrett Wollman 		 * If no new MTU was suggested, then we guess a new one
3315cbf3e08SGarrett Wollman 		 * less than the current value.  If the new MTU is
3325cbf3e08SGarrett Wollman 		 * unreasonably small (arbitrarily set at 296), then
3335cbf3e08SGarrett Wollman 		 * we reset the MTU to the interface value and enable the
3345cbf3e08SGarrett Wollman 		 * lock bit, indicating that we are no longer doing MTU
3355cbf3e08SGarrett Wollman 		 * discovery.
3365cbf3e08SGarrett Wollman 		 */
3375cbf3e08SGarrett Wollman 		if (code == PRC_MSGSIZE) {
3385cbf3e08SGarrett Wollman 			struct rtentry *rt;
3395cbf3e08SGarrett Wollman 			int mtu;
3405cbf3e08SGarrett Wollman 
3415cbf3e08SGarrett Wollman 			rt = rtalloc1((struct sockaddr *)&icmpsrc, 0,
3425cbf3e08SGarrett Wollman 				      RTF_CLONING | RTF_PRCLONING);
3435cbf3e08SGarrett Wollman 			if (rt && (rt->rt_flags & RTF_HOST)
3445cbf3e08SGarrett Wollman 			    && !(rt->rt_rmx.rmx_locks & RTV_MTU)) {
3455cbf3e08SGarrett Wollman 				mtu = ntohs(icp->icmp_nextmtu);
3465cbf3e08SGarrett Wollman 				if (!mtu)
3475cbf3e08SGarrett Wollman 					mtu = ip_next_mtu(rt->rt_rmx.rmx_mtu,
3485cbf3e08SGarrett Wollman 							  1);
349be070f43SGarrett Wollman #ifdef DEBUG_MTUDISC
350be070f43SGarrett Wollman 				printf("MTU for %s reduced to %d\n",
351be070f43SGarrett Wollman 					inet_ntoa(icmpsrc.sin_addr), mtu);
352be070f43SGarrett Wollman #endif
353be070f43SGarrett Wollman 				if (mtu < 296) {
354b7a44e34SGarrett Wollman 					/* rt->rt_rmx.rmx_mtu =
355b7a44e34SGarrett Wollman 						rt->rt_ifp->if_mtu; */
3565cbf3e08SGarrett Wollman 					rt->rt_rmx.rmx_locks |= RTV_MTU;
3575cbf3e08SGarrett Wollman 				} else if (rt->rt_rmx.rmx_mtu > mtu) {
3585cbf3e08SGarrett Wollman 					rt->rt_rmx.rmx_mtu = mtu;
3595cbf3e08SGarrett Wollman 				}
3605cbf3e08SGarrett Wollman 			}
3615cbf3e08SGarrett Wollman 			if (rt)
3625cbf3e08SGarrett Wollman 				RTFREE(rt);
3635cbf3e08SGarrett Wollman 		}
3645cbf3e08SGarrett Wollman 
365b7a44e34SGarrett Wollman #endif
366623ae52eSPoul-Henning Kamp 		ctlfunc = inetsw[ip_protox[icp->icmp_ip.ip_p]].pr_ctlinput;
367623ae52eSPoul-Henning Kamp 		if (ctlfunc)
368df8bae1dSRodney W. Grimes 			(*ctlfunc)(code, (struct sockaddr *)&icmpsrc,
369b62d102cSBruce Evans 				   (void *)&icp->icmp_ip);
370df8bae1dSRodney W. Grimes 		break;
371df8bae1dSRodney W. Grimes 
372df8bae1dSRodney W. Grimes 	badcode:
373df8bae1dSRodney W. Grimes 		icmpstat.icps_badcode++;
374df8bae1dSRodney W. Grimes 		break;
375df8bae1dSRodney W. Grimes 
376df8bae1dSRodney W. Grimes 	case ICMP_ECHO:
3777022ea0aSGarrett Wollman 		if (!icmpbmcastecho
3787022ea0aSGarrett Wollman 		    && (m->m_flags & (M_MCAST | M_BCAST)) != 0
3797022ea0aSGarrett Wollman 		    && IN_MULTICAST(ntohl(ip->ip_dst.s_addr))) {
3807022ea0aSGarrett Wollman 			icmpstat.icps_bmcastecho++;
3817022ea0aSGarrett Wollman 			break;
3827022ea0aSGarrett Wollman 		}
383df8bae1dSRodney W. Grimes 		icp->icmp_type = ICMP_ECHOREPLY;
384df8bae1dSRodney W. Grimes 		goto reflect;
385df8bae1dSRodney W. Grimes 
386df8bae1dSRodney W. Grimes 	case ICMP_TSTAMP:
387df8bae1dSRodney W. Grimes 		if (icmplen < ICMP_TSLEN) {
388df8bae1dSRodney W. Grimes 			icmpstat.icps_badlen++;
389df8bae1dSRodney W. Grimes 			break;
390df8bae1dSRodney W. Grimes 		}
391df8bae1dSRodney W. Grimes 		icp->icmp_type = ICMP_TSTAMPREPLY;
392df8bae1dSRodney W. Grimes 		icp->icmp_rtime = iptime();
393df8bae1dSRodney W. Grimes 		icp->icmp_ttime = icp->icmp_rtime;	/* bogus, do later! */
394df8bae1dSRodney W. Grimes 		goto reflect;
395df8bae1dSRodney W. Grimes 
396df8bae1dSRodney W. Grimes 	case ICMP_MASKREQ:
397df8bae1dSRodney W. Grimes #define	satosin(sa)	((struct sockaddr_in *)(sa))
398df8bae1dSRodney W. Grimes 		if (icmpmaskrepl == 0)
399df8bae1dSRodney W. Grimes 			break;
400df8bae1dSRodney W. Grimes 		/*
401df8bae1dSRodney W. Grimes 		 * We are not able to respond with all ones broadcast
402df8bae1dSRodney W. Grimes 		 * unless we receive it over a point-to-point interface.
403df8bae1dSRodney W. Grimes 		 */
404df8bae1dSRodney W. Grimes 		if (icmplen < ICMP_MASKLEN)
405df8bae1dSRodney W. Grimes 			break;
406df8bae1dSRodney W. Grimes 		switch (ip->ip_dst.s_addr) {
407df8bae1dSRodney W. Grimes 
408df8bae1dSRodney W. Grimes 		case INADDR_BROADCAST:
409df8bae1dSRodney W. Grimes 		case INADDR_ANY:
410df8bae1dSRodney W. Grimes 			icmpdst.sin_addr = ip->ip_src;
411df8bae1dSRodney W. Grimes 			break;
412df8bae1dSRodney W. Grimes 
413df8bae1dSRodney W. Grimes 		default:
414df8bae1dSRodney W. Grimes 			icmpdst.sin_addr = ip->ip_dst;
415df8bae1dSRodney W. Grimes 		}
416df8bae1dSRodney W. Grimes 		ia = (struct in_ifaddr *)ifaof_ifpforaddr(
417df8bae1dSRodney W. Grimes 			    (struct sockaddr *)&icmpdst, m->m_pkthdr.rcvif);
418df8bae1dSRodney W. Grimes 		if (ia == 0)
419df8bae1dSRodney W. Grimes 			break;
4207e6f7714SPoul-Henning Kamp 		if (ia->ia_ifp == 0)
4217e6f7714SPoul-Henning Kamp 			break;
422df8bae1dSRodney W. Grimes 		icp->icmp_type = ICMP_MASKREPLY;
423df8bae1dSRodney W. Grimes 		icp->icmp_mask = ia->ia_sockmask.sin_addr.s_addr;
424df8bae1dSRodney W. Grimes 		if (ip->ip_src.s_addr == 0) {
425df8bae1dSRodney W. Grimes 			if (ia->ia_ifp->if_flags & IFF_BROADCAST)
426df8bae1dSRodney W. Grimes 			    ip->ip_src = satosin(&ia->ia_broadaddr)->sin_addr;
427df8bae1dSRodney W. Grimes 			else if (ia->ia_ifp->if_flags & IFF_POINTOPOINT)
428df8bae1dSRodney W. Grimes 			    ip->ip_src = satosin(&ia->ia_dstaddr)->sin_addr;
429df8bae1dSRodney W. Grimes 		}
430df8bae1dSRodney W. Grimes reflect:
431df8bae1dSRodney W. Grimes 		ip->ip_len += hlen;	/* since ip_input deducts this */
432df8bae1dSRodney W. Grimes 		icmpstat.icps_reflect++;
433df8bae1dSRodney W. Grimes 		icmpstat.icps_outhist[icp->icmp_type]++;
434df8bae1dSRodney W. Grimes 		icmp_reflect(m);
435df8bae1dSRodney W. Grimes 		return;
436df8bae1dSRodney W. Grimes 
437df8bae1dSRodney W. Grimes 	case ICMP_REDIRECT:
438df8bae1dSRodney W. Grimes 		if (code > 3)
439df8bae1dSRodney W. Grimes 			goto badcode;
440df8bae1dSRodney W. Grimes 		if (icmplen < ICMP_ADVLENMIN || icmplen < ICMP_ADVLEN(icp) ||
4415e2d0696SGarrett Wollman 		    IP_VHL_HL(icp->icmp_ip.ip_vhl) < (sizeof(struct ip) >> 2)) {
442df8bae1dSRodney W. Grimes 			icmpstat.icps_badlen++;
443df8bae1dSRodney W. Grimes 			break;
444df8bae1dSRodney W. Grimes 		}
445df8bae1dSRodney W. Grimes 		/*
446df8bae1dSRodney W. Grimes 		 * Short circuit routing redirects to force
447df8bae1dSRodney W. Grimes 		 * immediate change in the kernel's routing
448df8bae1dSRodney W. Grimes 		 * tables.  The message is also handed to anyone
449df8bae1dSRodney W. Grimes 		 * listening on a raw socket (e.g. the routing
450df8bae1dSRodney W. Grimes 		 * daemon for use in updating its tables).
451df8bae1dSRodney W. Grimes 		 */
452df8bae1dSRodney W. Grimes 		icmpgw.sin_addr = ip->ip_src;
453df8bae1dSRodney W. Grimes 		icmpdst.sin_addr = icp->icmp_gwaddr;
454df8bae1dSRodney W. Grimes #ifdef	ICMPPRINTFS
4552b758395SGarrett Wollman 		if (icmpprintfs) {
4562b758395SGarrett Wollman 			char buf[4 * sizeof "123"];
4572b758395SGarrett Wollman 			strcpy(buf, inet_ntoa(icp->icmp_ip.ip_dst));
4582b758395SGarrett Wollman 
4592b758395SGarrett Wollman 			printf("redirect dst %s to %s\n",
4602b758395SGarrett Wollman 			       buf, inet_ntoa(icp->icmp_gwaddr));
4612b758395SGarrett Wollman 		}
462df8bae1dSRodney W. Grimes #endif
463df8bae1dSRodney W. Grimes 		icmpsrc.sin_addr = icp->icmp_ip.ip_dst;
464df8bae1dSRodney W. Grimes 		rtredirect((struct sockaddr *)&icmpsrc,
465df8bae1dSRodney W. Grimes 		  (struct sockaddr *)&icmpdst,
466df8bae1dSRodney W. Grimes 		  (struct sockaddr *)0, RTF_GATEWAY | RTF_HOST,
467df8bae1dSRodney W. Grimes 		  (struct sockaddr *)&icmpgw, (struct rtentry **)0);
468df8bae1dSRodney W. Grimes 		pfctlinput(PRC_REDIRECT_HOST, (struct sockaddr *)&icmpsrc);
469df8bae1dSRodney W. Grimes 		break;
470df8bae1dSRodney W. Grimes 
471df8bae1dSRodney W. Grimes 	/*
472df8bae1dSRodney W. Grimes 	 * No kernel processing for the following;
473df8bae1dSRodney W. Grimes 	 * just fall through to send to raw listener.
474df8bae1dSRodney W. Grimes 	 */
475df8bae1dSRodney W. Grimes 	case ICMP_ECHOREPLY:
476df8bae1dSRodney W. Grimes 	case ICMP_ROUTERADVERT:
477df8bae1dSRodney W. Grimes 	case ICMP_ROUTERSOLICIT:
478df8bae1dSRodney W. Grimes 	case ICMP_TSTAMPREPLY:
479df8bae1dSRodney W. Grimes 	case ICMP_IREQREPLY:
480df8bae1dSRodney W. Grimes 	case ICMP_MASKREPLY:
481df8bae1dSRodney W. Grimes 	default:
482df8bae1dSRodney W. Grimes 		break;
483df8bae1dSRodney W. Grimes 	}
484df8bae1dSRodney W. Grimes 
485df8bae1dSRodney W. Grimes raw:
486e62b8c49SBill Fenner 	rip_input(m, hlen);
487df8bae1dSRodney W. Grimes 	return;
488df8bae1dSRodney W. Grimes 
489df8bae1dSRodney W. Grimes freeit:
490df8bae1dSRodney W. Grimes 	m_freem(m);
491df8bae1dSRodney W. Grimes }
492df8bae1dSRodney W. Grimes 
493df8bae1dSRodney W. Grimes /*
494df8bae1dSRodney W. Grimes  * Reflect the ip packet back to the source
495df8bae1dSRodney W. Grimes  */
4960312fbe9SPoul-Henning Kamp static void
497df8bae1dSRodney W. Grimes icmp_reflect(m)
498df8bae1dSRodney W. Grimes 	struct mbuf *m;
499df8bae1dSRodney W. Grimes {
500df8bae1dSRodney W. Grimes 	register struct ip *ip = mtod(m, struct ip *);
501df8bae1dSRodney W. Grimes 	register struct in_ifaddr *ia;
502df8bae1dSRodney W. Grimes 	struct in_addr t;
503b5e8ce9fSBruce Evans 	struct mbuf *opts = 0;
5045e2d0696SGarrett Wollman 	int optlen = (IP_VHL_HL(ip->ip_vhl) << 2) - sizeof(struct ip);
505df8bae1dSRodney W. Grimes 
506df8bae1dSRodney W. Grimes 	if (!in_canforward(ip->ip_src) &&
507df8bae1dSRodney W. Grimes 	    ((ntohl(ip->ip_src.s_addr) & IN_CLASSA_NET) !=
508df8bae1dSRodney W. Grimes 	     (IN_LOOPBACKNET << IN_CLASSA_NSHIFT))) {
509df8bae1dSRodney W. Grimes 		m_freem(m);	/* Bad return address */
510df8bae1dSRodney W. Grimes 		goto done;	/* Ip_output() will check for broadcast */
511df8bae1dSRodney W. Grimes 	}
512df8bae1dSRodney W. Grimes 	t = ip->ip_dst;
513df8bae1dSRodney W. Grimes 	ip->ip_dst = ip->ip_src;
514df8bae1dSRodney W. Grimes 	/*
515df8bae1dSRodney W. Grimes 	 * If the incoming packet was addressed directly to us,
516df8bae1dSRodney W. Grimes 	 * use dst as the src for the reply.  Otherwise (broadcast
517df8bae1dSRodney W. Grimes 	 * or anonymous), use the address which corresponds
518df8bae1dSRodney W. Grimes 	 * to the incoming interface.
519df8bae1dSRodney W. Grimes 	 */
52059562606SGarrett Wollman 	for (ia = in_ifaddrhead.tqh_first; ia; ia = ia->ia_link.tqe_next) {
521df8bae1dSRodney W. Grimes 		if (t.s_addr == IA_SIN(ia)->sin_addr.s_addr)
522df8bae1dSRodney W. Grimes 			break;
5237e6f7714SPoul-Henning Kamp 		if (ia->ia_ifp && (ia->ia_ifp->if_flags & IFF_BROADCAST) &&
524df8bae1dSRodney W. Grimes 		    t.s_addr == satosin(&ia->ia_broadaddr)->sin_addr.s_addr)
525df8bae1dSRodney W. Grimes 			break;
526df8bae1dSRodney W. Grimes 	}
527df8bae1dSRodney W. Grimes 	icmpdst.sin_addr = t;
52841fbdc96SJulian Elischer 	if ((ia == (struct in_ifaddr *)0) && m->m_pkthdr.rcvif)
529df8bae1dSRodney W. Grimes 		ia = (struct in_ifaddr *)ifaof_ifpforaddr(
530df8bae1dSRodney W. Grimes 			(struct sockaddr *)&icmpdst, m->m_pkthdr.rcvif);
531df8bae1dSRodney W. Grimes 	/*
532df8bae1dSRodney W. Grimes 	 * The following happens if the packet was not addressed to us,
533df8bae1dSRodney W. Grimes 	 * and was received on an interface with no IP address.
534df8bae1dSRodney W. Grimes 	 */
535df8bae1dSRodney W. Grimes 	if (ia == (struct in_ifaddr *)0)
53659562606SGarrett Wollman 		ia = in_ifaddrhead.tqh_first;
537df8bae1dSRodney W. Grimes 	t = IA_SIN(ia)->sin_addr;
538df8bae1dSRodney W. Grimes 	ip->ip_src = t;
539df8bae1dSRodney W. Grimes 	ip->ip_ttl = MAXTTL;
540df8bae1dSRodney W. Grimes 
541df8bae1dSRodney W. Grimes 	if (optlen > 0) {
542df8bae1dSRodney W. Grimes 		register u_char *cp;
543df8bae1dSRodney W. Grimes 		int opt, cnt;
544df8bae1dSRodney W. Grimes 		u_int len;
545df8bae1dSRodney W. Grimes 
546df8bae1dSRodney W. Grimes 		/*
547df8bae1dSRodney W. Grimes 		 * Retrieve any source routing from the incoming packet;
548df8bae1dSRodney W. Grimes 		 * add on any record-route or timestamp options.
549df8bae1dSRodney W. Grimes 		 */
550df8bae1dSRodney W. Grimes 		cp = (u_char *) (ip + 1);
551df8bae1dSRodney W. Grimes 		if ((opts = ip_srcroute()) == 0 &&
552df8bae1dSRodney W. Grimes 		    (opts = m_gethdr(M_DONTWAIT, MT_HEADER))) {
553df8bae1dSRodney W. Grimes 			opts->m_len = sizeof(struct in_addr);
554df8bae1dSRodney W. Grimes 			mtod(opts, struct in_addr *)->s_addr = 0;
555df8bae1dSRodney W. Grimes 		}
556df8bae1dSRodney W. Grimes 		if (opts) {
557df8bae1dSRodney W. Grimes #ifdef ICMPPRINTFS
558df8bae1dSRodney W. Grimes 		    if (icmpprintfs)
559df8bae1dSRodney W. Grimes 			    printf("icmp_reflect optlen %d rt %d => ",
560df8bae1dSRodney W. Grimes 				optlen, opts->m_len);
561df8bae1dSRodney W. Grimes #endif
562df8bae1dSRodney W. Grimes 		    for (cnt = optlen; cnt > 0; cnt -= len, cp += len) {
563df8bae1dSRodney W. Grimes 			    opt = cp[IPOPT_OPTVAL];
564df8bae1dSRodney W. Grimes 			    if (opt == IPOPT_EOL)
565df8bae1dSRodney W. Grimes 				    break;
566df8bae1dSRodney W. Grimes 			    if (opt == IPOPT_NOP)
567df8bae1dSRodney W. Grimes 				    len = 1;
568df8bae1dSRodney W. Grimes 			    else {
569df8bae1dSRodney W. Grimes 				    len = cp[IPOPT_OLEN];
570df8bae1dSRodney W. Grimes 				    if (len <= 0 || len > cnt)
571df8bae1dSRodney W. Grimes 					    break;
572df8bae1dSRodney W. Grimes 			    }
573df8bae1dSRodney W. Grimes 			    /*
574df8bae1dSRodney W. Grimes 			     * Should check for overflow, but it "can't happen"
575df8bae1dSRodney W. Grimes 			     */
576df8bae1dSRodney W. Grimes 			    if (opt == IPOPT_RR || opt == IPOPT_TS ||
577df8bae1dSRodney W. Grimes 				opt == IPOPT_SECURITY) {
578df8bae1dSRodney W. Grimes 				    bcopy((caddr_t)cp,
579df8bae1dSRodney W. Grimes 					mtod(opts, caddr_t) + opts->m_len, len);
580df8bae1dSRodney W. Grimes 				    opts->m_len += len;
581df8bae1dSRodney W. Grimes 			    }
582df8bae1dSRodney W. Grimes 		    }
583df8bae1dSRodney W. Grimes 		    /* Terminate & pad, if necessary */
584623ae52eSPoul-Henning Kamp 		    cnt = opts->m_len % 4;
585623ae52eSPoul-Henning Kamp 		    if (cnt) {
586df8bae1dSRodney W. Grimes 			    for (; cnt < 4; cnt++) {
587df8bae1dSRodney W. Grimes 				    *(mtod(opts, caddr_t) + opts->m_len) =
588df8bae1dSRodney W. Grimes 					IPOPT_EOL;
589df8bae1dSRodney W. Grimes 				    opts->m_len++;
590df8bae1dSRodney W. Grimes 			    }
591df8bae1dSRodney W. Grimes 		    }
592df8bae1dSRodney W. Grimes #ifdef ICMPPRINTFS
593df8bae1dSRodney W. Grimes 		    if (icmpprintfs)
594df8bae1dSRodney W. Grimes 			    printf("%d\n", opts->m_len);
595df8bae1dSRodney W. Grimes #endif
596df8bae1dSRodney W. Grimes 		}
597df8bae1dSRodney W. Grimes 		/*
598df8bae1dSRodney W. Grimes 		 * Now strip out original options by copying rest of first
599df8bae1dSRodney W. Grimes 		 * mbuf's data back, and adjust the IP length.
600df8bae1dSRodney W. Grimes 		 */
601df8bae1dSRodney W. Grimes 		ip->ip_len -= optlen;
6025e2d0696SGarrett Wollman 		ip->ip_vhl = IP_VHL_BORING;
603df8bae1dSRodney W. Grimes 		m->m_len -= optlen;
604df8bae1dSRodney W. Grimes 		if (m->m_flags & M_PKTHDR)
605df8bae1dSRodney W. Grimes 			m->m_pkthdr.len -= optlen;
606df8bae1dSRodney W. Grimes 		optlen += sizeof(struct ip);
607df8bae1dSRodney W. Grimes 		bcopy((caddr_t)ip + optlen, (caddr_t)(ip + 1),
608df8bae1dSRodney W. Grimes 			 (unsigned)(m->m_len - sizeof(struct ip)));
609df8bae1dSRodney W. Grimes 	}
610df8bae1dSRodney W. Grimes 	m->m_flags &= ~(M_BCAST|M_MCAST);
611df8bae1dSRodney W. Grimes 	icmp_send(m, opts);
612df8bae1dSRodney W. Grimes done:
613df8bae1dSRodney W. Grimes 	if (opts)
614df8bae1dSRodney W. Grimes 		(void)m_free(opts);
615df8bae1dSRodney W. Grimes }
616df8bae1dSRodney W. Grimes 
617df8bae1dSRodney W. Grimes /*
618df8bae1dSRodney W. Grimes  * Send an icmp packet back to the ip level,
619df8bae1dSRodney W. Grimes  * after supplying a checksum.
620df8bae1dSRodney W. Grimes  */
6210312fbe9SPoul-Henning Kamp static void
622df8bae1dSRodney W. Grimes icmp_send(m, opts)
623df8bae1dSRodney W. Grimes 	register struct mbuf *m;
624df8bae1dSRodney W. Grimes 	struct mbuf *opts;
625df8bae1dSRodney W. Grimes {
626df8bae1dSRodney W. Grimes 	register struct ip *ip = mtod(m, struct ip *);
627df8bae1dSRodney W. Grimes 	register int hlen;
628df8bae1dSRodney W. Grimes 	register struct icmp *icp;
629d3d20ad1SGarrett Wollman 	struct route ro;
630df8bae1dSRodney W. Grimes 
6315e2d0696SGarrett Wollman 	hlen = IP_VHL_HL(ip->ip_vhl) << 2;
632df8bae1dSRodney W. Grimes 	m->m_data += hlen;
633df8bae1dSRodney W. Grimes 	m->m_len -= hlen;
634df8bae1dSRodney W. Grimes 	icp = mtod(m, struct icmp *);
635df8bae1dSRodney W. Grimes 	icp->icmp_cksum = 0;
636df8bae1dSRodney W. Grimes 	icp->icmp_cksum = in_cksum(m, ip->ip_len - hlen);
637df8bae1dSRodney W. Grimes 	m->m_data -= hlen;
638df8bae1dSRodney W. Grimes 	m->m_len += hlen;
639df8bae1dSRodney W. Grimes #ifdef ICMPPRINTFS
6402b758395SGarrett Wollman 	if (icmpprintfs) {
6412b758395SGarrett Wollman 		char buf[4 * sizeof "123"];
6422b758395SGarrett Wollman 		strcpy(buf, inet_ntoa(ip->ip_dst));
6432b758395SGarrett Wollman 		printf("icmp_send dst %s src %s\n",
6442b758395SGarrett Wollman 		       buf, inet_ntoa(ip->ip_src));
6452b758395SGarrett Wollman 	}
646df8bae1dSRodney W. Grimes #endif
647d3d20ad1SGarrett Wollman 	bzero(&ro, sizeof ro);
648d3d20ad1SGarrett Wollman 	(void) ip_output(m, opts, &ro, 0, NULL);
649d3d20ad1SGarrett Wollman 	if (ro.ro_rt)
650d3d20ad1SGarrett Wollman 		RTFREE(ro.ro_rt);
651df8bae1dSRodney W. Grimes }
652df8bae1dSRodney W. Grimes 
653df8bae1dSRodney W. Grimes n_time
654df8bae1dSRodney W. Grimes iptime()
655df8bae1dSRodney W. Grimes {
656df8bae1dSRodney W. Grimes 	struct timeval atv;
657df8bae1dSRodney W. Grimes 	u_long t;
658df8bae1dSRodney W. Grimes 
659df8bae1dSRodney W. Grimes 	microtime(&atv);
660df8bae1dSRodney W. Grimes 	t = (atv.tv_sec % (24*60*60)) * 1000 + atv.tv_usec / 1000;
661df8bae1dSRodney W. Grimes 	return (htonl(t));
662df8bae1dSRodney W. Grimes }
663df8bae1dSRodney W. Grimes 
664b7a44e34SGarrett Wollman #if 1
6655cbf3e08SGarrett Wollman /*
6665cbf3e08SGarrett Wollman  * Return the next larger or smaller MTU plateau (table from RFC 1191)
6675cbf3e08SGarrett Wollman  * given current value MTU.  If DIR is less than zero, a larger plateau
6685cbf3e08SGarrett Wollman  * is returned; otherwise, a smaller value is returned.
6695cbf3e08SGarrett Wollman  */
670f708ef1bSPoul-Henning Kamp static int
6715cbf3e08SGarrett Wollman ip_next_mtu(mtu, dir)
6725cbf3e08SGarrett Wollman 	int mtu;
6735cbf3e08SGarrett Wollman 	int dir;
6745cbf3e08SGarrett Wollman {
6755cbf3e08SGarrett Wollman 	static int mtutab[] = {
6765cbf3e08SGarrett Wollman 		65535, 32000, 17914, 8166, 4352, 2002, 1492, 1006, 508, 296,
6775cbf3e08SGarrett Wollman 		68, 0
6785cbf3e08SGarrett Wollman 	};
6795cbf3e08SGarrett Wollman 	int i;
6805cbf3e08SGarrett Wollman 
6815cbf3e08SGarrett Wollman 	for (i = 0; i < (sizeof mtutab) / (sizeof mtutab[0]); i++) {
6825cbf3e08SGarrett Wollman 		if (mtu >= mtutab[i])
6835cbf3e08SGarrett Wollman 			break;
6845cbf3e08SGarrett Wollman 	}
6855cbf3e08SGarrett Wollman 
6865cbf3e08SGarrett Wollman 	if (dir < 0) {
6875cbf3e08SGarrett Wollman 		if (i == 0) {
6885cbf3e08SGarrett Wollman 			return 0;
6895cbf3e08SGarrett Wollman 		} else {
6905cbf3e08SGarrett Wollman 			return mtutab[i - 1];
6915cbf3e08SGarrett Wollman 		}
6925cbf3e08SGarrett Wollman 	} else {
6935cbf3e08SGarrett Wollman 		if (mtutab[i] == 0) {
6945cbf3e08SGarrett Wollman 			return 0;
6955cbf3e08SGarrett Wollman 		} else if(mtu > mtutab[i]) {
6965cbf3e08SGarrett Wollman 			return mtutab[i];
6975cbf3e08SGarrett Wollman 		} else {
6985cbf3e08SGarrett Wollman 			return mtutab[i + 1];
6995cbf3e08SGarrett Wollman 		}
7005cbf3e08SGarrett Wollman 	}
7015cbf3e08SGarrett Wollman }
702b7a44e34SGarrett Wollman #endif
703