xref: /csrg-svn/sys/netinet/ip_icmp.c (revision 65457)
123182Smckusick /*
263218Sbostic  * Copyright (c) 1982, 1986, 1988, 1993
363218Sbostic  *	The Regents of the University of California.  All rights reserved.
423182Smckusick  *
544478Sbostic  * %sccs.include.redist.c%
632787Sbostic  *
7*65457Sbostic  *	@(#)ip_icmp.c	8.2 (Berkeley) 01/04/94
823182Smckusick  */
94785Swnj 
1056531Sbostic #include <sys/param.h>
1156531Sbostic #include <sys/systm.h>
1256531Sbostic #include <sys/malloc.h>
1356531Sbostic #include <sys/mbuf.h>
1456531Sbostic #include <sys/protosw.h>
1556531Sbostic #include <sys/socket.h>
1656531Sbostic #include <sys/time.h>
1756531Sbostic #include <sys/kernel.h>
188694Sroot 
1961335Sbostic #include <net/if.h>
2056531Sbostic #include <net/route.h>
2110891Ssam 
2256531Sbostic #include <netinet/in.h>
2356531Sbostic #include <netinet/in_systm.h>
2456531Sbostic #include <netinet/in_var.h>
2556531Sbostic #include <netinet/ip.h>
2656531Sbostic #include <netinet/ip_icmp.h>
2756531Sbostic #include <netinet/icmp_var.h>
284785Swnj 
294785Swnj /*
304785Swnj  * ICMP routines: error generation, receive packet processing, and
314785Swnj  * routines to turnaround packets back to the originator, and
324785Swnj  * host table maintenance routines.
334785Swnj  */
3459135Smckusick 
3559135Smckusick int	icmpmaskrepl = 0;
3640684Skarels #ifdef ICMPPRINTFS
376608Ssam int	icmpprintfs = 0;
3815027Smckusick #endif
394785Swnj 
4048463Skarels extern	struct protosw inetsw[];
4148463Skarels 
424785Swnj /*
436583Ssam  * Generate an error packet of type error
446583Ssam  * in response to bad packet ip.
454785Swnj  */
4660637Smckusick void
icmp_error(n,type,code,dest,destifp)4757433Sandrew icmp_error(n, type, code, dest, destifp)
4840684Skarels 	struct mbuf *n;
4912764Ssam 	int type, code;
5060637Smckusick 	n_long dest;
5157433Sandrew 	struct ifnet *destifp;
524785Swnj {
5340684Skarels 	register struct ip *oip = mtod(n, struct ip *), *nip;
546583Ssam 	register unsigned oiplen = oip->ip_hl << 2;
556583Ssam 	register struct icmp *icp;
5635794Skarels 	register struct mbuf *m;
5726383Skarels 	unsigned icmplen;
584785Swnj 
5915027Smckusick #ifdef ICMPPRINTFS
606590Ssam 	if (icmpprintfs)
616590Ssam 		printf("icmp_error(%x, %d, %d)\n", oip, type, code);
6215027Smckusick #endif
6326034Skarels 	if (type != ICMP_REDIRECT)
6426034Skarels 		icmpstat.icps_error++;
654785Swnj 	/*
6624811Skarels 	 * Don't send error if not the first fragment of message.
6731399Skarels 	 * Don't error if the old packet protocol was ICMP
6831399Skarels 	 * error message, only known informational types.
694785Swnj 	 */
7024811Skarels 	if (oip->ip_off &~ (IP_MF|IP_DF))
7140684Skarels 		goto freeit;
7231399Skarels 	if (oip->ip_p == IPPROTO_ICMP && type != ICMP_REDIRECT &&
7340684Skarels 	  n->m_len >= oiplen + ICMP_MINLEN &&
7431399Skarels 	  !ICMP_INFOTYPE(((struct icmp *)((caddr_t)oip + oiplen))->icmp_type)) {
7511532Ssam 		icmpstat.icps_oldicmp++;
7640684Skarels 		goto freeit;
7711532Ssam 	}
7854716Ssklower 	/* Don't send error in response to a multicast or broadcast packet */
7958998Ssklower 	if (n->m_flags & (M_BCAST|M_MCAST))
8054716Ssklower 		goto freeit;
814785Swnj 	/*
826583Ssam 	 * First, formulate icmp message
834785Swnj 	 */
8440684Skarels 	m = m_gethdr(M_DONTWAIT, MT_HEADER);
8511532Ssam 	if (m == NULL)
8640684Skarels 		goto freeit;
8735794Skarels 	icmplen = oiplen + min(8, oip->ip_len);
8824811Skarels 	m->m_len = icmplen + ICMP_MINLEN;
8940684Skarels 	MH_ALIGN(m, m->m_len);
906583Ssam 	icp = mtod(m, struct icmp *);
9124811Skarels 	if ((u_int)type > ICMP_MAXTYPE)
9211532Ssam 		panic("icmp_error");
9311532Ssam 	icmpstat.icps_outhist[type]++;
944785Swnj 	icp->icmp_type = type;
9524811Skarels 	if (type == ICMP_REDIRECT)
9660637Smckusick 		icp->icmp_gwaddr.s_addr = dest;
9757433Sandrew 	else {
9824811Skarels 		icp->icmp_void = 0;
9957433Sandrew 		/*
10057433Sandrew 		 * The following assignments assume an overlay with the
10157433Sandrew 		 * zeroed icmp_void field.
10257433Sandrew 		 */
10357433Sandrew 		if (type == ICMP_PARAMPROB) {
10457433Sandrew 			icp->icmp_pptr = code;
10557433Sandrew 			code = 0;
10657433Sandrew 		} else if (type == ICMP_UNREACH &&
10757433Sandrew 			code == ICMP_UNREACH_NEEDFRAG && destifp) {
10857433Sandrew 			icp->icmp_nextmtu = htons(destifp->if_mtu);
10957433Sandrew 		}
1106583Ssam 	}
11157433Sandrew 
1126583Ssam 	icp->icmp_code = code;
11324811Skarels 	bcopy((caddr_t)oip, (caddr_t)&icp->icmp_ip, icmplen);
1146590Ssam 	nip = &icp->icmp_ip;
11535794Skarels 	nip->ip_len = htons((u_short)(nip->ip_len + oiplen));
1164785Swnj 
1174785Swnj 	/*
11836817Skarels 	 * Now, copy old ip header (without options)
11936817Skarels 	 * in front of icmp message.
1204785Swnj 	 */
12140684Skarels 	if (m->m_data - sizeof(struct ip) < m->m_pktdat)
12224811Skarels 		panic("icmp len");
12340684Skarels 	m->m_data -= sizeof(struct ip);
12436817Skarels 	m->m_len += sizeof(struct ip);
12540684Skarels 	m->m_pkthdr.len = m->m_len;
12640684Skarels 	m->m_pkthdr.rcvif = n->m_pkthdr.rcvif;
1276583Ssam 	nip = mtod(m, struct ip *);
12857433Sandrew 	bcopy((caddr_t)oip, (caddr_t)nip, sizeof(struct ip));
12927063Skarels 	nip->ip_len = m->m_len;
13036817Skarels 	nip->ip_hl = sizeof(struct ip) >> 2;
1316583Ssam 	nip->ip_p = IPPROTO_ICMP;
13257433Sandrew 	nip->ip_tos = 0;
13340684Skarels 	icmp_reflect(m);
1344785Swnj 
13540684Skarels freeit:
13640684Skarels 	m_freem(n);
1374785Swnj }
1384785Swnj 
13940684Skarels static struct sockaddr_in icmpsrc = { sizeof (struct sockaddr_in), AF_INET };
14040684Skarels static struct sockaddr_in icmpdst = { sizeof (struct sockaddr_in), AF_INET };
14140684Skarels static struct sockaddr_in icmpgw = { sizeof (struct sockaddr_in), AF_INET };
14240684Skarels struct sockaddr_in icmpmask = { 8, 0 };
1436583Ssam 
1444785Swnj /*
1454801Swnj  * Process a received ICMP message.
1464785Swnj  */
14761335Sbostic void
icmp_input(m,hlen)14840684Skarels icmp_input(m, hlen)
14927194Skarels 	register struct mbuf *m;
15040684Skarels 	int hlen;
1514785Swnj {
1524801Swnj 	register struct icmp *icp;
1534801Swnj 	register struct ip *ip = mtod(m, struct ip *);
15440684Skarels 	int icmplen = ip->ip_len;
15516171Skarels 	register int i;
15624811Skarels 	struct in_ifaddr *ia;
15761335Sbostic 	void (*ctlfunc) __P((int, struct sockaddr *, struct ip *));
15861335Sbostic 	int code;
1595172Swnj 	extern u_char ip_protox[];
1604785Swnj 
1614785Swnj 	/*
1624785Swnj 	 * Locate icmp structure in mbuf, and check
1634785Swnj 	 * that not corrupted and of at least minimum length.
1644785Swnj 	 */
16515027Smckusick #ifdef ICMPPRINTFS
1666590Ssam 	if (icmpprintfs)
16758998Ssklower 		printf("icmp_input from %x to %x, len %d\n",
16858998Ssklower 			ntohl(ip->ip_src.s_addr), ntohl(ip->ip_dst.s_addr),
16958998Ssklower 			icmplen);
17015027Smckusick #endif
17115913Skarels 	if (icmplen < ICMP_MINLEN) {
17211532Ssam 		icmpstat.icps_tooshort++;
17340684Skarels 		goto freeit;
17411532Ssam 	}
17555066Spendry 	i = hlen + min(icmplen, ICMP_ADVLENMIN);
17654716Ssklower 	if (m->m_len < i && (m = m_pullup(m, i)) == 0)  {
17715831Skarels 		icmpstat.icps_tooshort++;
17815831Skarels 		return;
17915831Skarels 	}
18054716Ssklower 	ip = mtod(m, struct ip *);
1814785Swnj 	m->m_len -= hlen;
18240684Skarels 	m->m_data += hlen;
1836583Ssam 	icp = mtod(m, struct icmp *);
18416171Skarels 	if (in_cksum(m, icmplen)) {
18511532Ssam 		icmpstat.icps_checksum++;
18640684Skarels 		goto freeit;
1876583Ssam 	}
18827063Skarels 	m->m_len += hlen;
18940684Skarels 	m->m_data -= hlen;
1904785Swnj 
19115027Smckusick #ifdef ICMPPRINTFS
1924785Swnj 	/*
1934785Swnj 	 * Message type specific processing.
1944785Swnj 	 */
1956590Ssam 	if (icmpprintfs)
1966590Ssam 		printf("icmp_input, type %d code %d\n", icp->icmp_type,
19715027Smckusick 		    icp->icmp_code);
19815027Smckusick #endif
19924811Skarels 	if (icp->icmp_type > ICMP_MAXTYPE)
20027194Skarels 		goto raw;
20111532Ssam 	icmpstat.icps_inhist[icp->icmp_type]++;
20215027Smckusick 	code = icp->icmp_code;
20311532Ssam 	switch (icp->icmp_type) {
2044785Swnj 
2054785Swnj 	case ICMP_UNREACH:
20657433Sandrew 		switch (code) {
20757433Sandrew 			case ICMP_UNREACH_NET:
20857433Sandrew 			case ICMP_UNREACH_HOST:
20957433Sandrew 			case ICMP_UNREACH_PROTOCOL:
21057433Sandrew 			case ICMP_UNREACH_PORT:
21157433Sandrew 			case ICMP_UNREACH_SRCFAIL:
21257433Sandrew 				code += PRC_UNREACH_NET;
21357433Sandrew 				break;
21457433Sandrew 
21557433Sandrew 			case ICMP_UNREACH_NEEDFRAG:
21657433Sandrew 				code = PRC_MSGSIZE;
21757433Sandrew 				break;
21857433Sandrew 
21957433Sandrew 			case ICMP_UNREACH_NET_UNKNOWN:
22057433Sandrew 			case ICMP_UNREACH_NET_PROHIB:
22157433Sandrew 			case ICMP_UNREACH_TOSNET:
22257433Sandrew 				code = PRC_UNREACH_NET;
22357433Sandrew 				break;
22457433Sandrew 
22557433Sandrew 			case ICMP_UNREACH_HOST_UNKNOWN:
22657433Sandrew 			case ICMP_UNREACH_ISOLATED:
22757433Sandrew 			case ICMP_UNREACH_HOST_PROHIB:
22857433Sandrew 			case ICMP_UNREACH_TOSHOST:
22957433Sandrew 				code = PRC_UNREACH_HOST;
23057433Sandrew 				break;
23157433Sandrew 
23257433Sandrew 			default:
23357433Sandrew 				goto badcode;
23457433Sandrew 		}
23515027Smckusick 		goto deliver;
23615027Smckusick 
2374785Swnj 	case ICMP_TIMXCEED:
23815027Smckusick 		if (code > 1)
23915027Smckusick 			goto badcode;
24015027Smckusick 		code += PRC_TIMXCEED_INTRANS;
24115027Smckusick 		goto deliver;
24215027Smckusick 
2434785Swnj 	case ICMP_PARAMPROB:
24457433Sandrew 		if (code > 1)
24515027Smckusick 			goto badcode;
24615027Smckusick 		code = PRC_PARAMPROB;
24715027Smckusick 		goto deliver;
24815027Smckusick 
2494785Swnj 	case ICMP_SOURCEQUENCH:
25015027Smckusick 		if (code)
25115027Smckusick 			goto badcode;
25215027Smckusick 		code = PRC_QUENCH;
25315027Smckusick 	deliver:
2544785Swnj 		/*
25515027Smckusick 		 * Problem with datagram; advise higher level routines.
2564785Swnj 		 */
25740684Skarels 		if (icmplen < ICMP_ADVLENMIN || icmplen < ICMP_ADVLEN(icp) ||
25840684Skarels 		    icp->icmp_ip.ip_hl < (sizeof(struct ip) >> 2)) {
25911532Ssam 			icmpstat.icps_badlen++;
26040684Skarels 			goto freeit;
26111532Ssam 		}
26240684Skarels 		NTOHS(icp->icmp_ip.ip_len);
26315027Smckusick #ifdef ICMPPRINTFS
2646590Ssam 		if (icmpprintfs)
2656590Ssam 			printf("deliver to protocol %d\n", icp->icmp_ip.ip_p);
26615027Smckusick #endif
26724811Skarels 		icmpsrc.sin_addr = icp->icmp_ip.ip_dst;
2689030Sroot 		if (ctlfunc = inetsw[ip_protox[icp->icmp_ip.ip_p]].pr_ctlinput)
26940684Skarels 			(*ctlfunc)(code, (struct sockaddr *)&icmpsrc,
27061335Sbostic 			    &icp->icmp_ip);
27127063Skarels 		break;
2724785Swnj 
27315027Smckusick 	badcode:
27415027Smckusick 		icmpstat.icps_badcode++;
27527063Skarels 		break;
27615027Smckusick 
2774785Swnj 	case ICMP_ECHO:
2784785Swnj 		icp->icmp_type = ICMP_ECHOREPLY;
2794785Swnj 		goto reflect;
2804785Swnj 
2814785Swnj 	case ICMP_TSTAMP:
28211532Ssam 		if (icmplen < ICMP_TSLEN) {
28311532Ssam 			icmpstat.icps_badlen++;
28427063Skarels 			break;
28511532Ssam 		}
2864785Swnj 		icp->icmp_type = ICMP_TSTAMPREPLY;
2874923Swnj 		icp->icmp_rtime = iptime();
2884785Swnj 		icp->icmp_ttime = icp->icmp_rtime;	/* bogus, do later! */
2894785Swnj 		goto reflect;
2904785Swnj 
29158998Ssklower 	case ICMP_MASKREQ:
29218373Skarels #define	satosin(sa)	((struct sockaddr_in *)(sa))
29359135Smckusick 		if (icmpmaskrepl == 0)
29459135Smckusick 			break;
29558998Ssklower 		/*
29658998Ssklower 		 * We are not able to respond with all ones broadcast
29758998Ssklower 		 * unless we receive it over a point-to-point interface.
29858998Ssklower 		 */
29958998Ssklower 		if (icmplen < ICMP_MASKLEN)
30058998Ssklower 			break;
30158998Ssklower 		switch (ip->ip_dst.s_addr) {
3024785Swnj 
30358998Ssklower 		case INADDR_BROADCAST:
30458998Ssklower 		case INADDR_ANY:
30558998Ssklower 			icmpdst.sin_addr = ip->ip_src;
30627063Skarels 			break;
30758998Ssklower 
30858998Ssklower 		default:
30958998Ssklower 			icmpdst.sin_addr = ip->ip_dst;
31058998Ssklower 		}
31158998Ssklower 		ia = (struct in_ifaddr *)ifaof_ifpforaddr(
31258998Ssklower 			    (struct sockaddr *)&icmpdst, m->m_pkthdr.rcvif);
31358998Ssklower 		if (ia == 0)
31458998Ssklower 			break;
31530362Skarels 		icp->icmp_type = ICMP_MASKREPLY;
31640684Skarels 		icp->icmp_mask = ia->ia_sockmask.sin_addr.s_addr;
31724811Skarels 		if (ip->ip_src.s_addr == 0) {
31824811Skarels 			if (ia->ia_ifp->if_flags & IFF_BROADCAST)
31924811Skarels 			    ip->ip_src = satosin(&ia->ia_broadaddr)->sin_addr;
32024811Skarels 			else if (ia->ia_ifp->if_flags & IFF_POINTOPOINT)
32124811Skarels 			    ip->ip_src = satosin(&ia->ia_dstaddr)->sin_addr;
32224811Skarels 		}
32327063Skarels reflect:
32427063Skarels 		ip->ip_len += hlen;	/* since ip_input deducts this */
32527063Skarels 		icmpstat.icps_reflect++;
32627063Skarels 		icmpstat.icps_outhist[icp->icmp_type]++;
32740684Skarels 		icmp_reflect(m);
32827063Skarels 		return;
32924811Skarels 
33011549Ssam 	case ICMP_REDIRECT:
33157433Sandrew 		if (code > 3)
33257433Sandrew 			goto badcode;
33357433Sandrew 		if (icmplen < ICMP_ADVLENMIN || icmplen < ICMP_ADVLEN(icp) ||
33457433Sandrew 		    icp->icmp_ip.ip_hl < (sizeof(struct ip) >> 2)) {
33557433Sandrew 			icmpstat.icps_badlen++;
33657433Sandrew 			break;
33757433Sandrew 		}
33811549Ssam 		/*
33911549Ssam 		 * Short circuit routing redirects to force
34011549Ssam 		 * immediate change in the kernel's routing
34111549Ssam 		 * tables.  The message is also handed to anyone
34211549Ssam 		 * listening on a raw socket (e.g. the routing
34317046Skarels 		 * daemon for use in updating its tables).
34411549Ssam 		 */
34524811Skarels 		icmpgw.sin_addr = ip->ip_src;
34615831Skarels 		icmpdst.sin_addr = icp->icmp_gwaddr;
34724811Skarels #ifdef	ICMPPRINTFS
34824811Skarels 		if (icmpprintfs)
34924811Skarels 			printf("redirect dst %x to %x\n", icp->icmp_ip.ip_dst,
35024811Skarels 				icp->icmp_gwaddr);
35124811Skarels #endif
35258998Ssklower 		icmpsrc.sin_addr = icp->icmp_ip.ip_dst;
35358998Ssklower 		rtredirect((struct sockaddr *)&icmpsrc,
35458998Ssklower 		  (struct sockaddr *)&icmpdst,
35558998Ssklower 		  (struct sockaddr *)0, RTF_GATEWAY | RTF_HOST,
35658998Ssklower 		  (struct sockaddr *)&icmpgw, (struct rtentry **)0);
35758998Ssklower 		pfctlinput(PRC_REDIRECT_HOST, (struct sockaddr *)&icmpsrc);
35827063Skarels 		break;
35915831Skarels 
36027063Skarels 	/*
36127063Skarels 	 * No kernel processing for the following;
36227063Skarels 	 * just fall through to send to raw listener.
36327063Skarels 	 */
36415831Skarels 	case ICMP_ECHOREPLY:
36557433Sandrew 	case ICMP_ROUTERADVERT:
36657433Sandrew 	case ICMP_ROUTERSOLICIT:
36715831Skarels 	case ICMP_TSTAMPREPLY:
36815831Skarels 	case ICMP_IREQREPLY:
36924811Skarels 	case ICMP_MASKREPLY:
3704785Swnj 	default:
37127063Skarels 		break;
3724785Swnj 	}
37327063Skarels 
37427194Skarels raw:
37554716Ssklower 	rip_input(m);
3769185Ssam 	return;
37727063Skarels 
37840684Skarels freeit:
37927063Skarels 	m_freem(m);
3804785Swnj }
3814785Swnj 
3824785Swnj /*
3834785Swnj  * Reflect the ip packet back to the source
3844785Swnj  */
38561335Sbostic void
icmp_reflect(m)38640684Skarels icmp_reflect(m)
38740684Skarels 	struct mbuf *m;
3884785Swnj {
38940684Skarels 	register struct ip *ip = mtod(m, struct ip *);
39018373Skarels 	register struct in_ifaddr *ia;
39124811Skarels 	struct in_addr t;
39228926Skarels 	struct mbuf *opts = 0, *ip_srcroute();
39327063Skarels 	int optlen = (ip->ip_hl << 2) - sizeof(struct ip);
3944785Swnj 
39558998Ssklower 	if (!in_canforward(ip->ip_src) &&
39658998Ssklower 	    ((ntohl(ip->ip_src.s_addr) & IN_CLASSA_NET) !=
39758998Ssklower 	     (IN_LOOPBACKNET << IN_CLASSA_NSHIFT))) {
39858998Ssklower 		m_freem(m);	/* Bad return address */
39958998Ssklower 		goto done;	/* Ip_output() will check for broadcast */
40058998Ssklower 	}
4016583Ssam 	t = ip->ip_dst;
40224811Skarels 	ip->ip_dst = ip->ip_src;
40324811Skarels 	/*
40424811Skarels 	 * If the incoming packet was addressed directly to us,
40524811Skarels 	 * use dst as the src for the reply.  Otherwise (broadcast
40624811Skarels 	 * or anonymous), use the address which corresponds
40724811Skarels 	 * to the incoming interface.
40824811Skarels 	 */
40924811Skarels 	for (ia = in_ifaddr; ia; ia = ia->ia_next) {
41024811Skarels 		if (t.s_addr == IA_SIN(ia)->sin_addr.s_addr)
41118373Skarels 			break;
41224811Skarels 		if ((ia->ia_ifp->if_flags & IFF_BROADCAST) &&
41324811Skarels 		    t.s_addr == satosin(&ia->ia_broadaddr)->sin_addr.s_addr)
41424811Skarels 			break;
41524811Skarels 	}
41658998Ssklower 	icmpdst.sin_addr = t;
41724811Skarels 	if (ia == (struct in_ifaddr *)0)
41858998Ssklower 		ia = (struct in_ifaddr *)ifaof_ifpforaddr(
41958998Ssklower 			(struct sockaddr *)&icmpdst, m->m_pkthdr.rcvif);
42058998Ssklower 	/*
42158998Ssklower 	 * The following happens if the packet was not addressed to us,
42258998Ssklower 	 * and was received on an interface with no IP address.
42358998Ssklower 	 */
42428344Skarels 	if (ia == (struct in_ifaddr *)0)
42528344Skarels 		ia = in_ifaddr;
42628344Skarels 	t = IA_SIN(ia)->sin_addr;
42724811Skarels 	ip->ip_src = t;
42830971Skarels 	ip->ip_ttl = MAXTTL;
42924811Skarels 
43027063Skarels 	if (optlen > 0) {
43136817Skarels 		register u_char *cp;
43240684Skarels 		int opt, cnt;
43336817Skarels 		u_int len;
43436817Skarels 
43526034Skarels 		/*
43636817Skarels 		 * Retrieve any source routing from the incoming packet;
43736817Skarels 		 * add on any record-route or timestamp options.
43826034Skarels 		 */
43936817Skarels 		cp = (u_char *) (ip + 1);
44036948Skarels 		if ((opts = ip_srcroute()) == 0 &&
44140684Skarels 		    (opts = m_gethdr(M_DONTWAIT, MT_HEADER))) {
44236948Skarels 			opts->m_len = sizeof(struct in_addr);
44336948Skarels 			mtod(opts, struct in_addr *)->s_addr = 0;
44436948Skarels 		}
44536948Skarels 		if (opts) {
44636948Skarels #ifdef ICMPPRINTFS
44736948Skarels 		    if (icmpprintfs)
44836948Skarels 			    printf("icmp_reflect optlen %d rt %d => ",
44936948Skarels 				optlen, opts->m_len);
45036948Skarels #endif
45136817Skarels 		    for (cnt = optlen; cnt > 0; cnt -= len, cp += len) {
45236948Skarels 			    opt = cp[IPOPT_OPTVAL];
45336948Skarels 			    if (opt == IPOPT_EOL)
45436948Skarels 				    break;
45536948Skarels 			    if (opt == IPOPT_NOP)
45636948Skarels 				    len = 1;
45736948Skarels 			    else {
45836948Skarels 				    len = cp[IPOPT_OLEN];
45936948Skarels 				    if (len <= 0 || len > cnt)
46036948Skarels 					    break;
46136948Skarels 			    }
46236948Skarels 			    /*
46357433Sandrew 			     * Should check for overflow, but it "can't happen"
46436948Skarels 			     */
46557433Sandrew 			    if (opt == IPOPT_RR || opt == IPOPT_TS ||
46657433Sandrew 				opt == IPOPT_SECURITY) {
46736948Skarels 				    bcopy((caddr_t)cp,
46836948Skarels 					mtod(opts, caddr_t) + opts->m_len, len);
46936948Skarels 				    opts->m_len += len;
47036948Skarels 			    }
47136948Skarels 		    }
47257433Sandrew 		    /* Terminate & pad, if necessary */
47357433Sandrew 		    if (cnt = opts->m_len % 4) {
47457433Sandrew 			    for (; cnt < 4; cnt++) {
47557433Sandrew 				    *(mtod(opts, caddr_t) + opts->m_len) =
47657433Sandrew 					IPOPT_EOL;
47757433Sandrew 				    opts->m_len++;
47857433Sandrew 			    }
47936948Skarels 		    }
48036948Skarels #ifdef ICMPPRINTFS
48136948Skarels 		    if (icmpprintfs)
48236948Skarels 			    printf("%d\n", opts->m_len);
48336948Skarels #endif
48436817Skarels 		}
48536948Skarels 		/*
48636948Skarels 		 * Now strip out original options by copying rest of first
48736948Skarels 		 * mbuf's data back, and adjust the IP length.
48836948Skarels 		 */
48926034Skarels 		ip->ip_len -= optlen;
49036817Skarels 		ip->ip_hl = sizeof(struct ip) >> 2;
49136948Skarels 		m->m_len -= optlen;
49240684Skarels 		if (m->m_flags & M_PKTHDR)
49340684Skarels 			m->m_pkthdr.len -= optlen;
49436948Skarels 		optlen += sizeof(struct ip);
49536948Skarels 		bcopy((caddr_t)ip + optlen, (caddr_t)(ip + 1),
49640684Skarels 			 (unsigned)(m->m_len - sizeof(struct ip)));
49724811Skarels 	}
49857939Ssklower 	m->m_flags &= ~(M_BCAST|M_MCAST);
49940684Skarels 	icmp_send(m, opts);
50058998Ssklower done:
50126034Skarels 	if (opts)
50226383Skarels 		(void)m_free(opts);
5034785Swnj }
5044785Swnj 
5054785Swnj /*
5066583Ssam  * Send an icmp packet back to the ip level,
5076583Ssam  * after supplying a checksum.
5084785Swnj  */
50961335Sbostic void
icmp_send(m,opts)51040684Skarels icmp_send(m, opts)
51140684Skarels 	register struct mbuf *m;
51226034Skarels 	struct mbuf *opts;
5134785Swnj {
51440684Skarels 	register struct ip *ip = mtod(m, struct ip *);
5159185Ssam 	register int hlen;
5166583Ssam 	register struct icmp *icp;
5176583Ssam 
5189185Ssam 	hlen = ip->ip_hl << 2;
51940684Skarels 	m->m_data += hlen;
52027063Skarels 	m->m_len -= hlen;
5216583Ssam 	icp = mtod(m, struct icmp *);
5226583Ssam 	icp->icmp_cksum = 0;
5236583Ssam 	icp->icmp_cksum = in_cksum(m, ip->ip_len - hlen);
52440684Skarels 	m->m_data -= hlen;
5256583Ssam 	m->m_len += hlen;
52615027Smckusick #ifdef ICMPPRINTFS
5276590Ssam 	if (icmpprintfs)
5286590Ssam 		printf("icmp_send dst %x src %x\n", ip->ip_dst, ip->ip_src);
52915027Smckusick #endif
53061335Sbostic 	(void) ip_output(m, opts, NULL, 0, NULL);
5314785Swnj }
5324785Swnj 
5334907Swnj n_time
iptime()5344923Swnj iptime()
5354801Swnj {
53625893Skarels 	struct timeval atv;
5374967Swnj 	u_long t;
5384801Swnj 
53925893Skarels 	microtime(&atv);
54025893Skarels 	t = (atv.tv_sec % (24*60*60)) * 1000 + atv.tv_usec / 1000;
5414907Swnj 	return (htonl(t));
5424801Swnj }
54359135Smckusick 
54461335Sbostic int
icmp_sysctl(name,namelen,oldp,oldlenp,newp,newlen)54559135Smckusick icmp_sysctl(name, namelen, oldp, oldlenp, newp, newlen)
54659135Smckusick 	int *name;
54759135Smckusick 	u_int namelen;
54859135Smckusick 	void *oldp;
54959135Smckusick 	size_t *oldlenp;
55059135Smckusick 	void *newp;
55159135Smckusick 	size_t newlen;
55259135Smckusick {
55359135Smckusick 
554*65457Sbostic 	/* All sysctl names at this level are terminal. */
55559135Smckusick 	if (namelen != 1)
55659135Smckusick 		return (ENOTDIR);
55759135Smckusick 
55859135Smckusick 	switch (name[0]) {
55959135Smckusick 	case ICMPCTL_MASKREPL:
56059135Smckusick 		return (sysctl_int(oldp, oldlenp, newp, newlen, &icmpmaskrepl));
56159135Smckusick 	default:
56259135Smckusick 		return (ENOPROTOOPT);
56359135Smckusick 	}
56459135Smckusick 	/* NOTREACHED */
56559135Smckusick }
566