ip_icmp.c revision 12881
11541Srgrimes/*
21541Srgrimes * Copyright (c) 1982, 1986, 1988, 1993
31541Srgrimes *	The Regents of the University of California.  All rights reserved.
41541Srgrimes *
51541Srgrimes * Redistribution and use in source and binary forms, with or without
61541Srgrimes * modification, are permitted provided that the following conditions
71541Srgrimes * are met:
81541Srgrimes * 1. Redistributions of source code must retain the above copyright
91541Srgrimes *    notice, this list of conditions and the following disclaimer.
101541Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
111541Srgrimes *    notice, this list of conditions and the following disclaimer in the
121541Srgrimes *    documentation and/or other materials provided with the distribution.
131541Srgrimes * 3. All advertising materials mentioning features or use of this software
141541Srgrimes *    must display the following acknowledgement:
151541Srgrimes *	This product includes software developed by the University of
161541Srgrimes *	California, Berkeley and its contributors.
171541Srgrimes * 4. Neither the name of the University nor the names of its contributors
181541Srgrimes *    may be used to endorse or promote products derived from this software
191541Srgrimes *    without specific prior written permission.
201541Srgrimes *
211541Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
221541Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
231541Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
241541Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
251541Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
261541Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
271541Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
281541Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
291541Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
301541Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
311541Srgrimes * SUCH DAMAGE.
321541Srgrimes *
331541Srgrimes *	@(#)ip_icmp.c	8.2 (Berkeley) 1/4/94
3412881Sbde * $Id: ip_icmp.c,v 1.16 1995/12/14 09:53:40 phk Exp $
351541Srgrimes */
361541Srgrimes
371541Srgrimes#include <sys/param.h>
381541Srgrimes#include <sys/systm.h>
391541Srgrimes#include <sys/malloc.h>
401541Srgrimes#include <sys/mbuf.h>
411541Srgrimes#include <sys/protosw.h>
421541Srgrimes#include <sys/socket.h>
431541Srgrimes#include <sys/time.h>
441541Srgrimes#include <sys/kernel.h>
453444Sphk#include <sys/socket.h>
467090Sbde#include <sys/sysctl.h>
471541Srgrimes
481541Srgrimes#include <net/if.h>
491541Srgrimes#include <net/route.h>
501541Srgrimes
511541Srgrimes#include <netinet/in.h>
521541Srgrimes#include <netinet/in_systm.h>
531541Srgrimes#include <netinet/in_var.h>
541541Srgrimes#include <netinet/ip.h>
551541Srgrimes#include <netinet/ip_icmp.h>
567090Sbde#include <netinet/ip_var.h>
571541Srgrimes#include <netinet/icmp_var.h>
581541Srgrimes
591541Srgrimes/*
601541Srgrimes * ICMP routines: error generation, receive packet processing, and
611541Srgrimes * routines to turnaround packets back to the originator, and
621541Srgrimes * host table maintenance routines.
631541Srgrimes */
641541Srgrimes
6512820Sphkstatic struct	icmpstat icmpstat;
6612296SphkSYSCTL_STRUCT(_net_inet_icmp, ICMPCTL_STATS, stats, CTLFLAG_RD,
6712296Sphk	&icmpstat, icmpstat, "");
6812296Sphk
6912296Sphkstatic int	icmpmaskrepl = 0;
7012296SphkSYSCTL_INT(_net_inet_icmp, ICMPCTL_MASKREPL, maskrepl, CTLFLAG_RW,
7112296Sphk	&icmpmaskrepl, 0, "");
7212296Sphk
731541Srgrimes#ifdef ICMPPRINTFS
741541Srgrimesint	icmpprintfs = 0;
751541Srgrimes#endif
761541Srgrimes
7712296Sphkstatic void	icmp_reflect __P((struct mbuf *));
7812296Sphkstatic void	icmp_send __P((struct mbuf *, struct mbuf *));
7912820Sphkstatic int	ip_next_mtu __P((int, int));
8012296Sphk
811541Srgrimesextern	struct protosw inetsw[];
821541Srgrimes
831541Srgrimes/*
841541Srgrimes * Generate an error packet of type error
851541Srgrimes * in response to bad packet ip.
861541Srgrimes */
871541Srgrimesvoid
881541Srgrimesicmp_error(n, type, code, dest, destifp)
891541Srgrimes	struct mbuf *n;
901541Srgrimes	int type, code;
911541Srgrimes	n_long dest;
921541Srgrimes	struct ifnet *destifp;
931541Srgrimes{
941541Srgrimes	register struct ip *oip = mtod(n, struct ip *), *nip;
951541Srgrimes	register unsigned oiplen = oip->ip_hl << 2;
961541Srgrimes	register struct icmp *icp;
971541Srgrimes	register struct mbuf *m;
981541Srgrimes	unsigned icmplen;
991541Srgrimes
1001541Srgrimes#ifdef ICMPPRINTFS
1011541Srgrimes	if (icmpprintfs)
1023311Sphk		printf("icmp_error(%p, %x, %d)\n", oip, type, code);
1031541Srgrimes#endif
1041541Srgrimes	if (type != ICMP_REDIRECT)
1051541Srgrimes		icmpstat.icps_error++;
1061541Srgrimes	/*
1071541Srgrimes	 * Don't send error if not the first fragment of message.
1081541Srgrimes	 * Don't error if the old packet protocol was ICMP
1091541Srgrimes	 * error message, only known informational types.
1101541Srgrimes	 */
1111541Srgrimes	if (oip->ip_off &~ (IP_MF|IP_DF))
1121541Srgrimes		goto freeit;
1131541Srgrimes	if (oip->ip_p == IPPROTO_ICMP && type != ICMP_REDIRECT &&
1141541Srgrimes	  n->m_len >= oiplen + ICMP_MINLEN &&
1151541Srgrimes	  !ICMP_INFOTYPE(((struct icmp *)((caddr_t)oip + oiplen))->icmp_type)) {
1161541Srgrimes		icmpstat.icps_oldicmp++;
1171541Srgrimes		goto freeit;
1181541Srgrimes	}
1191541Srgrimes	/* Don't send error in response to a multicast or broadcast packet */
1201541Srgrimes	if (n->m_flags & (M_BCAST|M_MCAST))
1211541Srgrimes		goto freeit;
1221541Srgrimes	/*
1231541Srgrimes	 * First, formulate icmp message
1241541Srgrimes	 */
1251541Srgrimes	m = m_gethdr(M_DONTWAIT, MT_HEADER);
1261541Srgrimes	if (m == NULL)
1271541Srgrimes		goto freeit;
1281541Srgrimes	icmplen = oiplen + min(8, oip->ip_len);
1291541Srgrimes	m->m_len = icmplen + ICMP_MINLEN;
1301541Srgrimes	MH_ALIGN(m, m->m_len);
1311541Srgrimes	icp = mtod(m, struct icmp *);
1321541Srgrimes	if ((u_int)type > ICMP_MAXTYPE)
1331541Srgrimes		panic("icmp_error");
1341541Srgrimes	icmpstat.icps_outhist[type]++;
1351541Srgrimes	icp->icmp_type = type;
1361541Srgrimes	if (type == ICMP_REDIRECT)
1371541Srgrimes		icp->icmp_gwaddr.s_addr = dest;
1381541Srgrimes	else {
1391541Srgrimes		icp->icmp_void = 0;
1408876Srgrimes		/*
1411541Srgrimes		 * The following assignments assume an overlay with the
1421541Srgrimes		 * zeroed icmp_void field.
1431541Srgrimes		 */
1441541Srgrimes		if (type == ICMP_PARAMPROB) {
1451541Srgrimes			icp->icmp_pptr = code;
1461541Srgrimes			code = 0;
1471541Srgrimes		} else if (type == ICMP_UNREACH &&
1481541Srgrimes			code == ICMP_UNREACH_NEEDFRAG && destifp) {
1491541Srgrimes			icp->icmp_nextmtu = htons(destifp->if_mtu);
1501541Srgrimes		}
1511541Srgrimes	}
1521541Srgrimes
1531541Srgrimes	icp->icmp_code = code;
1541541Srgrimes	bcopy((caddr_t)oip, (caddr_t)&icp->icmp_ip, icmplen);
1551541Srgrimes	nip = &icp->icmp_ip;
1561541Srgrimes	nip->ip_len = htons((u_short)(nip->ip_len + oiplen));
1571541Srgrimes
1581541Srgrimes	/*
1591541Srgrimes	 * Now, copy old ip header (without options)
1601541Srgrimes	 * in front of icmp message.
1611541Srgrimes	 */
1621541Srgrimes	if (m->m_data - sizeof(struct ip) < m->m_pktdat)
1631541Srgrimes		panic("icmp len");
1641541Srgrimes	m->m_data -= sizeof(struct ip);
1651541Srgrimes	m->m_len += sizeof(struct ip);
1661541Srgrimes	m->m_pkthdr.len = m->m_len;
1671541Srgrimes	m->m_pkthdr.rcvif = n->m_pkthdr.rcvif;
1681541Srgrimes	nip = mtod(m, struct ip *);
1691541Srgrimes	bcopy((caddr_t)oip, (caddr_t)nip, sizeof(struct ip));
1701541Srgrimes	nip->ip_len = m->m_len;
1711541Srgrimes	nip->ip_hl = sizeof(struct ip) >> 2;
1721541Srgrimes	nip->ip_p = IPPROTO_ICMP;
1731541Srgrimes	nip->ip_tos = 0;
1741541Srgrimes	icmp_reflect(m);
1751541Srgrimes
1761541Srgrimesfreeit:
1771541Srgrimes	m_freem(n);
1781541Srgrimes}
1791541Srgrimes
1801541Srgrimesstatic struct sockaddr_in icmpsrc = { sizeof (struct sockaddr_in), AF_INET };
1811541Srgrimesstatic struct sockaddr_in icmpdst = { sizeof (struct sockaddr_in), AF_INET };
1821541Srgrimesstatic struct sockaddr_in icmpgw = { sizeof (struct sockaddr_in), AF_INET };
1831541Srgrimes
1841541Srgrimes/*
1851541Srgrimes * Process a received ICMP message.
1861541Srgrimes */
1871541Srgrimesvoid
1881541Srgrimesicmp_input(m, hlen)
1891541Srgrimes	register struct mbuf *m;
1901541Srgrimes	int hlen;
1911541Srgrimes{
1921541Srgrimes	register struct icmp *icp;
1931541Srgrimes	register struct ip *ip = mtod(m, struct ip *);
1941541Srgrimes	int icmplen = ip->ip_len;
1951541Srgrimes	register int i;
1961541Srgrimes	struct in_ifaddr *ia;
19712881Sbde	void (*ctlfunc) __P((int, struct sockaddr *, void *));
1981541Srgrimes	int code;
1991541Srgrimes
2001541Srgrimes	/*
2011541Srgrimes	 * Locate icmp structure in mbuf, and check
2021541Srgrimes	 * that not corrupted and of at least minimum length.
2031541Srgrimes	 */
2041541Srgrimes#ifdef ICMPPRINTFS
20510421Swollman	if (icmpprintfs) {
20610421Swollman		char buf[4 * sizeof "123"];
20710421Swollman		strcpy(buf, inet_ntoa(ip->ip_src));
20810421Swollman		printf("icmp_input from %s to %s, len %d\n",
20910421Swollman		       buf, inet_ntoa(ip->ip_dst), icmplen);
21010421Swollman	}
2111541Srgrimes#endif
2121541Srgrimes	if (icmplen < ICMP_MINLEN) {
2131541Srgrimes		icmpstat.icps_tooshort++;
2141541Srgrimes		goto freeit;
2151541Srgrimes	}
2161541Srgrimes	i = hlen + min(icmplen, ICMP_ADVLENMIN);
2171541Srgrimes	if (m->m_len < i && (m = m_pullup(m, i)) == 0)  {
2181541Srgrimes		icmpstat.icps_tooshort++;
2191541Srgrimes		return;
2201541Srgrimes	}
2211541Srgrimes	ip = mtod(m, struct ip *);
2221541Srgrimes	m->m_len -= hlen;
2231541Srgrimes	m->m_data += hlen;
2241541Srgrimes	icp = mtod(m, struct icmp *);
2251541Srgrimes	if (in_cksum(m, icmplen)) {
2261541Srgrimes		icmpstat.icps_checksum++;
2271541Srgrimes		goto freeit;
2281541Srgrimes	}
2291541Srgrimes	m->m_len += hlen;
2301541Srgrimes	m->m_data -= hlen;
2311541Srgrimes
2321541Srgrimes#ifdef ICMPPRINTFS
2331541Srgrimes	if (icmpprintfs)
2341541Srgrimes		printf("icmp_input, type %d code %d\n", icp->icmp_type,
2351541Srgrimes		    icp->icmp_code);
2361541Srgrimes#endif
2379472Swollman
2389472Swollman	/*
2399472Swollman	 * Message type specific processing.
2409472Swollman	 */
2411541Srgrimes	if (icp->icmp_type > ICMP_MAXTYPE)
2421541Srgrimes		goto raw;
2431541Srgrimes	icmpstat.icps_inhist[icp->icmp_type]++;
2441541Srgrimes	code = icp->icmp_code;
2451541Srgrimes	switch (icp->icmp_type) {
2461541Srgrimes
2471541Srgrimes	case ICMP_UNREACH:
2481541Srgrimes		switch (code) {
2491541Srgrimes			case ICMP_UNREACH_NET:
2501541Srgrimes			case ICMP_UNREACH_HOST:
2511541Srgrimes			case ICMP_UNREACH_PROTOCOL:
2521541Srgrimes			case ICMP_UNREACH_PORT:
2531541Srgrimes			case ICMP_UNREACH_SRCFAIL:
2541541Srgrimes				code += PRC_UNREACH_NET;
2551541Srgrimes				break;
2561541Srgrimes
2571541Srgrimes			case ICMP_UNREACH_NEEDFRAG:
2581541Srgrimes				code = PRC_MSGSIZE;
2591541Srgrimes				break;
2608876Srgrimes
2611541Srgrimes			case ICMP_UNREACH_NET_UNKNOWN:
2621541Srgrimes			case ICMP_UNREACH_NET_PROHIB:
2631541Srgrimes			case ICMP_UNREACH_TOSNET:
2641541Srgrimes				code = PRC_UNREACH_NET;
2651541Srgrimes				break;
2661541Srgrimes
2671541Srgrimes			case ICMP_UNREACH_HOST_UNKNOWN:
2681541Srgrimes			case ICMP_UNREACH_ISOLATED:
2691541Srgrimes			case ICMP_UNREACH_HOST_PROHIB:
2701541Srgrimes			case ICMP_UNREACH_TOSHOST:
2711541Srgrimes				code = PRC_UNREACH_HOST;
2721541Srgrimes				break;
2731541Srgrimes
2741541Srgrimes			default:
2751541Srgrimes				goto badcode;
2761541Srgrimes		}
2771541Srgrimes		goto deliver;
2781541Srgrimes
2791541Srgrimes	case ICMP_TIMXCEED:
2801541Srgrimes		if (code > 1)
2811541Srgrimes			goto badcode;
2821541Srgrimes		code += PRC_TIMXCEED_INTRANS;
2831541Srgrimes		goto deliver;
2841541Srgrimes
2851541Srgrimes	case ICMP_PARAMPROB:
2861541Srgrimes		if (code > 1)
2871541Srgrimes			goto badcode;
2881541Srgrimes		code = PRC_PARAMPROB;
2891541Srgrimes		goto deliver;
2901541Srgrimes
2911541Srgrimes	case ICMP_SOURCEQUENCH:
2921541Srgrimes		if (code)
2931541Srgrimes			goto badcode;
2941541Srgrimes		code = PRC_QUENCH;
2951541Srgrimes	deliver:
2961541Srgrimes		/*
2971541Srgrimes		 * Problem with datagram; advise higher level routines.
2981541Srgrimes		 */
2991541Srgrimes		if (icmplen < ICMP_ADVLENMIN || icmplen < ICMP_ADVLEN(icp) ||
3001541Srgrimes		    icp->icmp_ip.ip_hl < (sizeof(struct ip) >> 2)) {
3011541Srgrimes			icmpstat.icps_badlen++;
3021541Srgrimes			goto freeit;
3031541Srgrimes		}
3041541Srgrimes		NTOHS(icp->icmp_ip.ip_len);
3059472Swollman		/* Discard ICMP's in response to multicast packets */
3069472Swollman		if (IN_MULTICAST(ntohl(icp->icmp_ip.ip_dst.s_addr)))
3079472Swollman			goto badcode;
3081541Srgrimes#ifdef ICMPPRINTFS
3091541Srgrimes		if (icmpprintfs)
3101541Srgrimes			printf("deliver to protocol %d\n", icp->icmp_ip.ip_p);
3111541Srgrimes#endif
3121541Srgrimes		icmpsrc.sin_addr = icp->icmp_ip.ip_dst;
31312635Swollman#if 1
31410881Swollman		/*
31510881Swollman		 * MTU discovery:
31610881Swollman		 * If we got a needfrag and there is a host route to the
31710881Swollman		 * original destination, and the MTU is not locked, then
31810881Swollman		 * set the MTU in the route to the suggested new value
31910881Swollman		 * (if given) and then notify as usual.  The ULPs will
32010881Swollman		 * notice that the MTU has changed and adapt accordingly.
32110881Swollman		 * If no new MTU was suggested, then we guess a new one
32210881Swollman		 * less than the current value.  If the new MTU is
32310881Swollman		 * unreasonably small (arbitrarily set at 296), then
32410881Swollman		 * we reset the MTU to the interface value and enable the
32510881Swollman		 * lock bit, indicating that we are no longer doing MTU
32610881Swollman		 * discovery.
32710881Swollman		 */
32810881Swollman		if (code == PRC_MSGSIZE) {
32910881Swollman			struct rtentry *rt;
33010881Swollman			int mtu;
33110881Swollman
33210881Swollman			rt = rtalloc1((struct sockaddr *)&icmpsrc, 0,
33310881Swollman				      RTF_CLONING | RTF_PRCLONING);
33410881Swollman			if (rt && (rt->rt_flags & RTF_HOST)
33510881Swollman			    && !(rt->rt_rmx.rmx_locks & RTV_MTU)) {
33610881Swollman				mtu = ntohs(icp->icmp_nextmtu);
33710881Swollman				if (!mtu)
33810881Swollman					mtu = ip_next_mtu(rt->rt_rmx.rmx_mtu,
33910881Swollman							  1);
34012676Swollman#ifdef DEBUG_MTUDISC
34112676Swollman				printf("MTU for %s reduced to %d\n",
34212676Swollman					inet_ntoa(icmpsrc.sin_addr), mtu);
34312676Swollman#endif
34412676Swollman				if (mtu < 296) {
34512635Swollman					/* rt->rt_rmx.rmx_mtu =
34612635Swollman						rt->rt_ifp->if_mtu; */
34710881Swollman					rt->rt_rmx.rmx_locks |= RTV_MTU;
34810881Swollman				} else if (rt->rt_rmx.rmx_mtu > mtu) {
34910881Swollman					rt->rt_rmx.rmx_mtu = mtu;
35010881Swollman				}
35110881Swollman			}
35210881Swollman			if (rt)
35310881Swollman				RTFREE(rt);
35410881Swollman		}
35510881Swollman
35612635Swollman#endif
3573311Sphk		ctlfunc = inetsw[ip_protox[icp->icmp_ip.ip_p]].pr_ctlinput;
3583311Sphk		if (ctlfunc)
3591541Srgrimes			(*ctlfunc)(code, (struct sockaddr *)&icmpsrc,
36012881Sbde				   (void *)&icp->icmp_ip);
3611541Srgrimes		break;
3621541Srgrimes
3631541Srgrimes	badcode:
3641541Srgrimes		icmpstat.icps_badcode++;
3651541Srgrimes		break;
3661541Srgrimes
3671541Srgrimes	case ICMP_ECHO:
3681541Srgrimes		icp->icmp_type = ICMP_ECHOREPLY;
3691541Srgrimes		goto reflect;
3701541Srgrimes
3711541Srgrimes	case ICMP_TSTAMP:
3721541Srgrimes		if (icmplen < ICMP_TSLEN) {
3731541Srgrimes			icmpstat.icps_badlen++;
3741541Srgrimes			break;
3751541Srgrimes		}
3761541Srgrimes		icp->icmp_type = ICMP_TSTAMPREPLY;
3771541Srgrimes		icp->icmp_rtime = iptime();
3781541Srgrimes		icp->icmp_ttime = icp->icmp_rtime;	/* bogus, do later! */
3791541Srgrimes		goto reflect;
3808876Srgrimes
3811541Srgrimes	case ICMP_MASKREQ:
3821541Srgrimes#define	satosin(sa)	((struct sockaddr_in *)(sa))
3831541Srgrimes		if (icmpmaskrepl == 0)
3841541Srgrimes			break;
3851541Srgrimes		/*
3861541Srgrimes		 * We are not able to respond with all ones broadcast
3871541Srgrimes		 * unless we receive it over a point-to-point interface.
3881541Srgrimes		 */
3891541Srgrimes		if (icmplen < ICMP_MASKLEN)
3901541Srgrimes			break;
3911541Srgrimes		switch (ip->ip_dst.s_addr) {
3921541Srgrimes
3931541Srgrimes		case INADDR_BROADCAST:
3941541Srgrimes		case INADDR_ANY:
3951541Srgrimes			icmpdst.sin_addr = ip->ip_src;
3961541Srgrimes			break;
3971541Srgrimes
3981541Srgrimes		default:
3991541Srgrimes			icmpdst.sin_addr = ip->ip_dst;
4001541Srgrimes		}
4011541Srgrimes		ia = (struct in_ifaddr *)ifaof_ifpforaddr(
4021541Srgrimes			    (struct sockaddr *)&icmpdst, m->m_pkthdr.rcvif);
4031541Srgrimes		if (ia == 0)
4041541Srgrimes			break;
4051541Srgrimes		icp->icmp_type = ICMP_MASKREPLY;
4061541Srgrimes		icp->icmp_mask = ia->ia_sockmask.sin_addr.s_addr;
4071541Srgrimes		if (ip->ip_src.s_addr == 0) {
4081541Srgrimes			if (ia->ia_ifp->if_flags & IFF_BROADCAST)
4091541Srgrimes			    ip->ip_src = satosin(&ia->ia_broadaddr)->sin_addr;
4101541Srgrimes			else if (ia->ia_ifp->if_flags & IFF_POINTOPOINT)
4111541Srgrimes			    ip->ip_src = satosin(&ia->ia_dstaddr)->sin_addr;
4121541Srgrimes		}
4131541Srgrimesreflect:
4141541Srgrimes		ip->ip_len += hlen;	/* since ip_input deducts this */
4151541Srgrimes		icmpstat.icps_reflect++;
4161541Srgrimes		icmpstat.icps_outhist[icp->icmp_type]++;
4171541Srgrimes		icmp_reflect(m);
4181541Srgrimes		return;
4191541Srgrimes
4201541Srgrimes	case ICMP_REDIRECT:
4211541Srgrimes		if (code > 3)
4221541Srgrimes			goto badcode;
4231541Srgrimes		if (icmplen < ICMP_ADVLENMIN || icmplen < ICMP_ADVLEN(icp) ||
4241541Srgrimes		    icp->icmp_ip.ip_hl < (sizeof(struct ip) >> 2)) {
4251541Srgrimes			icmpstat.icps_badlen++;
4261541Srgrimes			break;
4271541Srgrimes		}
4281541Srgrimes		/*
4291541Srgrimes		 * Short circuit routing redirects to force
4301541Srgrimes		 * immediate change in the kernel's routing
4311541Srgrimes		 * tables.  The message is also handed to anyone
4321541Srgrimes		 * listening on a raw socket (e.g. the routing
4331541Srgrimes		 * daemon for use in updating its tables).
4341541Srgrimes		 */
4351541Srgrimes		icmpgw.sin_addr = ip->ip_src;
4361541Srgrimes		icmpdst.sin_addr = icp->icmp_gwaddr;
4371541Srgrimes#ifdef	ICMPPRINTFS
43810421Swollman		if (icmpprintfs) {
43910421Swollman			char buf[4 * sizeof "123"];
44010421Swollman			strcpy(buf, inet_ntoa(icp->icmp_ip.ip_dst));
44110421Swollman
44210421Swollman			printf("redirect dst %s to %s\n",
44310421Swollman			       buf, inet_ntoa(icp->icmp_gwaddr));
44410421Swollman		}
4451541Srgrimes#endif
4461541Srgrimes		icmpsrc.sin_addr = icp->icmp_ip.ip_dst;
4471541Srgrimes		rtredirect((struct sockaddr *)&icmpsrc,
4481541Srgrimes		  (struct sockaddr *)&icmpdst,
4491541Srgrimes		  (struct sockaddr *)0, RTF_GATEWAY | RTF_HOST,
4501541Srgrimes		  (struct sockaddr *)&icmpgw, (struct rtentry **)0);
4511541Srgrimes		pfctlinput(PRC_REDIRECT_HOST, (struct sockaddr *)&icmpsrc);
4521541Srgrimes		break;
4531541Srgrimes
4541541Srgrimes	/*
4551541Srgrimes	 * No kernel processing for the following;
4561541Srgrimes	 * just fall through to send to raw listener.
4571541Srgrimes	 */
4581541Srgrimes	case ICMP_ECHOREPLY:
4591541Srgrimes	case ICMP_ROUTERADVERT:
4601541Srgrimes	case ICMP_ROUTERSOLICIT:
4611541Srgrimes	case ICMP_TSTAMPREPLY:
4621541Srgrimes	case ICMP_IREQREPLY:
4631541Srgrimes	case ICMP_MASKREPLY:
4641541Srgrimes	default:
4651541Srgrimes		break;
4661541Srgrimes	}
4671541Srgrimes
4681541Srgrimesraw:
4691541Srgrimes	rip_input(m);
4701541Srgrimes	return;
4711541Srgrimes
4721541Srgrimesfreeit:
4731541Srgrimes	m_freem(m);
4741541Srgrimes}
4751541Srgrimes
4761541Srgrimes/*
4771541Srgrimes * Reflect the ip packet back to the source
4781541Srgrimes */
47912296Sphkstatic void
4801541Srgrimesicmp_reflect(m)
4811541Srgrimes	struct mbuf *m;
4821541Srgrimes{
4831541Srgrimes	register struct ip *ip = mtod(m, struct ip *);
4841541Srgrimes	register struct in_ifaddr *ia;
4851541Srgrimes	struct in_addr t;
4867090Sbde	struct mbuf *opts = 0;
4871541Srgrimes	int optlen = (ip->ip_hl << 2) - sizeof(struct ip);
4881541Srgrimes
4891541Srgrimes	if (!in_canforward(ip->ip_src) &&
4901541Srgrimes	    ((ntohl(ip->ip_src.s_addr) & IN_CLASSA_NET) !=
4911541Srgrimes	     (IN_LOOPBACKNET << IN_CLASSA_NSHIFT))) {
4921541Srgrimes		m_freem(m);	/* Bad return address */
4931541Srgrimes		goto done;	/* Ip_output() will check for broadcast */
4941541Srgrimes	}
4951541Srgrimes	t = ip->ip_dst;
4961541Srgrimes	ip->ip_dst = ip->ip_src;
4971541Srgrimes	/*
4981541Srgrimes	 * If the incoming packet was addressed directly to us,
4991541Srgrimes	 * use dst as the src for the reply.  Otherwise (broadcast
5001541Srgrimes	 * or anonymous), use the address which corresponds
5011541Srgrimes	 * to the incoming interface.
5021541Srgrimes	 */
5031541Srgrimes	for (ia = in_ifaddr; ia; ia = ia->ia_next) {
5041541Srgrimes		if (t.s_addr == IA_SIN(ia)->sin_addr.s_addr)
5051541Srgrimes			break;
5061541Srgrimes		if ((ia->ia_ifp->if_flags & IFF_BROADCAST) &&
5071541Srgrimes		    t.s_addr == satosin(&ia->ia_broadaddr)->sin_addr.s_addr)
5081541Srgrimes			break;
5091541Srgrimes	}
5101541Srgrimes	icmpdst.sin_addr = t;
5111541Srgrimes	if (ia == (struct in_ifaddr *)0)
5121541Srgrimes		ia = (struct in_ifaddr *)ifaof_ifpforaddr(
5131541Srgrimes			(struct sockaddr *)&icmpdst, m->m_pkthdr.rcvif);
5141541Srgrimes	/*
5151541Srgrimes	 * The following happens if the packet was not addressed to us,
5161541Srgrimes	 * and was received on an interface with no IP address.
5171541Srgrimes	 */
5181541Srgrimes	if (ia == (struct in_ifaddr *)0)
5191541Srgrimes		ia = in_ifaddr;
5201541Srgrimes	t = IA_SIN(ia)->sin_addr;
5211541Srgrimes	ip->ip_src = t;
5221541Srgrimes	ip->ip_ttl = MAXTTL;
5231541Srgrimes
5241541Srgrimes	if (optlen > 0) {
5251541Srgrimes		register u_char *cp;
5261541Srgrimes		int opt, cnt;
5271541Srgrimes		u_int len;
5281541Srgrimes
5291541Srgrimes		/*
5301541Srgrimes		 * Retrieve any source routing from the incoming packet;
5311541Srgrimes		 * add on any record-route or timestamp options.
5321541Srgrimes		 */
5331541Srgrimes		cp = (u_char *) (ip + 1);
5341541Srgrimes		if ((opts = ip_srcroute()) == 0 &&
5351541Srgrimes		    (opts = m_gethdr(M_DONTWAIT, MT_HEADER))) {
5361541Srgrimes			opts->m_len = sizeof(struct in_addr);
5371541Srgrimes			mtod(opts, struct in_addr *)->s_addr = 0;
5381541Srgrimes		}
5391541Srgrimes		if (opts) {
5401541Srgrimes#ifdef ICMPPRINTFS
5411541Srgrimes		    if (icmpprintfs)
5421541Srgrimes			    printf("icmp_reflect optlen %d rt %d => ",
5431541Srgrimes				optlen, opts->m_len);
5441541Srgrimes#endif
5451541Srgrimes		    for (cnt = optlen; cnt > 0; cnt -= len, cp += len) {
5461541Srgrimes			    opt = cp[IPOPT_OPTVAL];
5471541Srgrimes			    if (opt == IPOPT_EOL)
5481541Srgrimes				    break;
5491541Srgrimes			    if (opt == IPOPT_NOP)
5501541Srgrimes				    len = 1;
5511541Srgrimes			    else {
5521541Srgrimes				    len = cp[IPOPT_OLEN];
5531541Srgrimes				    if (len <= 0 || len > cnt)
5541541Srgrimes					    break;
5551541Srgrimes			    }
5561541Srgrimes			    /*
5571541Srgrimes			     * Should check for overflow, but it "can't happen"
5581541Srgrimes			     */
5598876Srgrimes			    if (opt == IPOPT_RR || opt == IPOPT_TS ||
5601541Srgrimes				opt == IPOPT_SECURITY) {
5611541Srgrimes				    bcopy((caddr_t)cp,
5621541Srgrimes					mtod(opts, caddr_t) + opts->m_len, len);
5631541Srgrimes				    opts->m_len += len;
5641541Srgrimes			    }
5651541Srgrimes		    }
5661541Srgrimes		    /* Terminate & pad, if necessary */
5673311Sphk		    cnt = opts->m_len % 4;
5683311Sphk		    if (cnt) {
5691541Srgrimes			    for (; cnt < 4; cnt++) {
5701541Srgrimes				    *(mtod(opts, caddr_t) + opts->m_len) =
5711541Srgrimes					IPOPT_EOL;
5721541Srgrimes				    opts->m_len++;
5731541Srgrimes			    }
5741541Srgrimes		    }
5751541Srgrimes#ifdef ICMPPRINTFS
5761541Srgrimes		    if (icmpprintfs)
5771541Srgrimes			    printf("%d\n", opts->m_len);
5781541Srgrimes#endif
5791541Srgrimes		}
5801541Srgrimes		/*
5811541Srgrimes		 * Now strip out original options by copying rest of first
5821541Srgrimes		 * mbuf's data back, and adjust the IP length.
5831541Srgrimes		 */
5841541Srgrimes		ip->ip_len -= optlen;
5851541Srgrimes		ip->ip_hl = sizeof(struct ip) >> 2;
5861541Srgrimes		m->m_len -= optlen;
5871541Srgrimes		if (m->m_flags & M_PKTHDR)
5881541Srgrimes			m->m_pkthdr.len -= optlen;
5891541Srgrimes		optlen += sizeof(struct ip);
5901541Srgrimes		bcopy((caddr_t)ip + optlen, (caddr_t)(ip + 1),
5911541Srgrimes			 (unsigned)(m->m_len - sizeof(struct ip)));
5921541Srgrimes	}
5931541Srgrimes	m->m_flags &= ~(M_BCAST|M_MCAST);
5941541Srgrimes	icmp_send(m, opts);
5951541Srgrimesdone:
5961541Srgrimes	if (opts)
5971541Srgrimes		(void)m_free(opts);
5981541Srgrimes}
5991541Srgrimes
6001541Srgrimes/*
6011541Srgrimes * Send an icmp packet back to the ip level,
6021541Srgrimes * after supplying a checksum.
6031541Srgrimes */
60412296Sphkstatic void
6051541Srgrimesicmp_send(m, opts)
6061541Srgrimes	register struct mbuf *m;
6071541Srgrimes	struct mbuf *opts;
6081541Srgrimes{
6091541Srgrimes	register struct ip *ip = mtod(m, struct ip *);
6101541Srgrimes	register int hlen;
6111541Srgrimes	register struct icmp *icp;
6121541Srgrimes
6131541Srgrimes	hlen = ip->ip_hl << 2;
6141541Srgrimes	m->m_data += hlen;
6151541Srgrimes	m->m_len -= hlen;
6161541Srgrimes	icp = mtod(m, struct icmp *);
6171541Srgrimes	icp->icmp_cksum = 0;
6181541Srgrimes	icp->icmp_cksum = in_cksum(m, ip->ip_len - hlen);
6191541Srgrimes	m->m_data -= hlen;
6201541Srgrimes	m->m_len += hlen;
6211541Srgrimes#ifdef ICMPPRINTFS
62210421Swollman	if (icmpprintfs) {
62310421Swollman		char buf[4 * sizeof "123"];
62410421Swollman		strcpy(buf, inet_ntoa(ip->ip_dst));
62510421Swollman		printf("icmp_send dst %s src %s\n",
62610421Swollman		       buf, inet_ntoa(ip->ip_src));
62710421Swollman	}
6281541Srgrimes#endif
6291541Srgrimes	(void) ip_output(m, opts, NULL, 0, NULL);
6301541Srgrimes}
6311541Srgrimes
6321541Srgrimesn_time
6331541Srgrimesiptime()
6341541Srgrimes{
6351541Srgrimes	struct timeval atv;
6361541Srgrimes	u_long t;
6371541Srgrimes
6381541Srgrimes	microtime(&atv);
6391541Srgrimes	t = (atv.tv_sec % (24*60*60)) * 1000 + atv.tv_usec / 1000;
6401541Srgrimes	return (htonl(t));
6411541Srgrimes}
6421541Srgrimes
64312635Swollman#if 1
64410881Swollman/*
64510881Swollman * Return the next larger or smaller MTU plateau (table from RFC 1191)
64610881Swollman * given current value MTU.  If DIR is less than zero, a larger plateau
64710881Swollman * is returned; otherwise, a smaller value is returned.
64810881Swollman */
64912820Sphkstatic int
65010881Swollmanip_next_mtu(mtu, dir)
65110881Swollman	int mtu;
65210881Swollman	int dir;
65310881Swollman{
65410881Swollman	static int mtutab[] = {
65510881Swollman		65535, 32000, 17914, 8166, 4352, 2002, 1492, 1006, 508, 296,
65610881Swollman		68, 0
65710881Swollman	};
65810881Swollman	int i;
65910881Swollman
66010881Swollman	for (i = 0; i < (sizeof mtutab) / (sizeof mtutab[0]); i++) {
66110881Swollman		if (mtu >= mtutab[i])
66210881Swollman			break;
66310881Swollman	}
66410881Swollman
66510881Swollman	if (dir < 0) {
66610881Swollman		if (i == 0) {
66710881Swollman			return 0;
66810881Swollman		} else {
66910881Swollman			return mtutab[i - 1];
67010881Swollman		}
67110881Swollman	} else {
67210881Swollman		if (mtutab[i] == 0) {
67310881Swollman			return 0;
67410881Swollman		} else if(mtu > mtutab[i]) {
67510881Swollman			return mtutab[i];
67610881Swollman		} else {
67710881Swollman			return mtutab[i + 1];
67810881Swollman		}
67910881Swollman	}
68010881Swollman}
68112635Swollman#endif
682