xref: /csrg-svn/sys/netinet/ip_icmp.c (revision 10891)
1*10891Ssam /*	ip_icmp.c	4.27	83/02/10	*/
24785Swnj 
34785Swnj #include "../h/param.h"
44923Swnj #include "../h/systm.h"
54785Swnj #include "../h/mbuf.h"
64907Swnj #include "../h/protosw.h"
76583Ssam #include "../h/socket.h"
8*10891Ssam #include "../h/time.h"
98694Sroot #include "../h/kernel.h"
108694Sroot 
118694Sroot #include "../net/route.h"
12*10891Ssam 
138398Swnj #include "../netinet/in.h"
148398Swnj #include "../netinet/in_systm.h"
158398Swnj #include "../netinet/ip.h"
168398Swnj #include "../netinet/ip_icmp.h"
174785Swnj 
184785Swnj /*
194785Swnj  * ICMP routines: error generation, receive packet processing, and
204785Swnj  * routines to turnaround packets back to the originator, and
214785Swnj  * host table maintenance routines.
224785Swnj  */
236608Ssam int	icmpprintfs = 0;
244785Swnj 
254785Swnj /*
266583Ssam  * Generate an error packet of type error
276583Ssam  * in response to bad packet ip.
284785Swnj  */
294785Swnj icmp_error(oip, type, code)
304785Swnj 	struct ip *oip;
316583Ssam 	int type, code;
324785Swnj {
336583Ssam 	register unsigned oiplen = oip->ip_hl << 2;
346583Ssam 	register struct icmp *icp;
354785Swnj 	struct mbuf *m;
364785Swnj 	struct ip *nip;
374785Swnj 
386590Ssam 	if (icmpprintfs)
396590Ssam 		printf("icmp_error(%x, %d, %d)\n", oip, type, code);
404785Swnj 	/*
414785Swnj 	 * Make sure that the old IP packet had 8 bytes of data to return;
424785Swnj 	 * if not, don't bother.  Also don't EVER error if the old
434785Swnj 	 * packet protocol was ICMP.
444785Swnj 	 */
456590Ssam 	if (oip->ip_len < 8 || oip->ip_p == IPPROTO_ICMP)
464785Swnj 		goto free;
474785Swnj 
484785Swnj 	/*
496583Ssam 	 * First, formulate icmp message
504785Swnj 	 */
519640Ssam 	m = m_get(M_DONTWAIT, MT_HEADER);
524785Swnj 	if (m == 0)
534785Swnj 		goto free;
546583Ssam 	m->m_len = oiplen + 8 + ICMP_MINLEN;
556583Ssam 	m->m_off = MMAXOFF - m->m_len;
566583Ssam 	icp = mtod(m, struct icmp *);
574785Swnj 	icp->icmp_type = type;
586583Ssam 	icp->icmp_void = 0;
594785Swnj 	if (type == ICMP_PARAMPROB) {
604785Swnj 		icp->icmp_pptr = code;
616583Ssam 		code = 0;
626583Ssam 	}
636583Ssam 	icp->icmp_code = code;
644801Swnj 	bcopy((caddr_t)oip, (caddr_t)&icp->icmp_ip, oiplen + 8);
656590Ssam 	nip = &icp->icmp_ip;
666590Ssam 	nip->ip_len += oiplen;
676590Ssam 	nip->ip_len = htons((u_short)nip->ip_len);
684785Swnj 
694785Swnj 	/*
706583Ssam 	 * Now, copy old ip header in front of icmp
716583Ssam 	 * message.  This allows us to reuse any source
726583Ssam 	 * routing info present.
734785Swnj 	 */
746583Ssam 	m->m_off -= oiplen;
756583Ssam 	nip = mtod(m, struct ip *);
766583Ssam 	bcopy((caddr_t)oip, (caddr_t)nip, oiplen);
776583Ssam 	nip->ip_len = m->m_len + oiplen;
786583Ssam 	nip->ip_p = IPPROTO_ICMP;
796583Ssam 	/* icmp_send adds ip header to m_off and m_len, so we deduct here */
806583Ssam 	m->m_off += oiplen;
814801Swnj 	icmp_reflect(nip);
824785Swnj 
836485Swnj free:
844785Swnj 	m_freem(dtom(oip));
854785Swnj }
864785Swnj 
876583Ssam static char icmpmap[] = {
886583Ssam 	-1,		 -1,		-1,
896583Ssam 	PRC_UNREACH_NET, PRC_QUENCH, 	PRC_REDIRECT_NET,
906583Ssam 	-1,		 -1,		-1,
916583Ssam 	-1,		 -1,		PRC_TIMXCEED_INTRANS,
926583Ssam 	PRC_PARAMPROB,	 -1,		-1,
936583Ssam 	-1,		 -1
946583Ssam };
956583Ssam 
966583Ssam static struct sockproto icmproto = { AF_INET, IPPROTO_ICMP };
976583Ssam static struct sockaddr_in icmpsrc = { AF_INET };
986583Ssam static struct sockaddr_in icmpdst = { AF_INET };
996583Ssam 
1004785Swnj /*
1014801Swnj  * Process a received ICMP message.
1024785Swnj  */
1034785Swnj icmp_input(m)
1044785Swnj 	struct mbuf *m;
1054785Swnj {
1064801Swnj 	register struct icmp *icp;
1074801Swnj 	register struct ip *ip = mtod(m, struct ip *);
1089185Ssam 	int icmplen = ip->ip_len, hlen = ip->ip_hl << 2;
1099185Ssam 	int i, (*ctlfunc)(), type;
1105172Swnj 	extern u_char ip_protox[];
1114785Swnj 
1124785Swnj 	/*
1134785Swnj 	 * Locate icmp structure in mbuf, and check
1144785Swnj 	 * that not corrupted and of at least minimum length.
1154785Swnj 	 */
1166590Ssam 	if (icmpprintfs)
1176590Ssam 		printf("icmp_input from %x, len %d\n", ip->ip_src, icmplen);
1186583Ssam 	if (icmplen < ICMP_MINLEN)
1196583Ssam 		goto free;
1204785Swnj 	m->m_len -= hlen;
1214785Swnj 	m->m_off += hlen;
1224785Swnj 	/* need routine to make sure header is in this mbuf here */
1236583Ssam 	icp = mtod(m, struct icmp *);
1244785Swnj 	i = icp->icmp_cksum;
1254785Swnj 	icp->icmp_cksum = 0;
1266583Ssam 	if (i != in_cksum(m, icmplen)) {
1276583Ssam 		printf("icmp: cksum %x\n", i);
1284801Swnj 		goto free;
1296583Ssam 	}
1304785Swnj 
1314785Swnj 	/*
1324785Swnj 	 * Message type specific processing.
1334785Swnj 	 */
1346590Ssam 	if (icmpprintfs)
1356590Ssam 		printf("icmp_input, type %d code %d\n", icp->icmp_type,
1366590Ssam 			icp->icmp_code);
1376583Ssam 	switch (i = icp->icmp_type) {
1384785Swnj 
1394785Swnj 	case ICMP_UNREACH:
1404785Swnj 	case ICMP_TIMXCEED:
1414785Swnj 	case ICMP_PARAMPROB:
1426583Ssam 	case ICMP_REDIRECT:
1434785Swnj 	case ICMP_SOURCEQUENCH:
1444785Swnj 		/*
1454785Swnj 		 * Problem with previous datagram; advise
1464785Swnj 		 * higher level routines.
1474785Swnj 		 */
1488637Sroot 		icp->icmp_ip.ip_len = ntohs((u_short)icp->icmp_ip.ip_len);
1494801Swnj 		if (icmplen < ICMP_ADVLENMIN || icmplen < ICMP_ADVLEN(icp))
1504801Swnj 			goto free;
1516590Ssam 		if (icmpprintfs)
1526590Ssam 			printf("deliver to protocol %d\n", icp->icmp_ip.ip_p);
1539185Ssam 		type = i == ICMP_PARAMPROB ? 0 : icp->icmp_code;
1549030Sroot 		if (ctlfunc = inetsw[ip_protox[icp->icmp_ip.ip_p]].pr_ctlinput)
1559185Ssam 			(*ctlfunc)(icmpmap[i] + type, (caddr_t)icp);
1564785Swnj 		goto free;
1574785Swnj 
1584785Swnj 	case ICMP_ECHO:
1594785Swnj 		icp->icmp_type = ICMP_ECHOREPLY;
1604785Swnj 		goto reflect;
1614785Swnj 
1624785Swnj 	case ICMP_TSTAMP:
1634801Swnj 		if (icmplen < ICMP_TSLEN)
1644801Swnj 			goto free;
1654785Swnj 		icp->icmp_type = ICMP_TSTAMPREPLY;
1664923Swnj 		icp->icmp_rtime = iptime();
1674785Swnj 		icp->icmp_ttime = icp->icmp_rtime;	/* bogus, do later! */
1684785Swnj 		goto reflect;
1694785Swnj 
1704785Swnj 	case ICMP_IREQ:
1714785Swnj 		/* fill in source address zero fields! */
1724785Swnj 		goto reflect;
1734785Swnj 
1744785Swnj 	case ICMP_ECHOREPLY:
1754785Swnj 	case ICMP_TSTAMPREPLY:
1764785Swnj 	case ICMP_IREQREPLY:
1774801Swnj 		if (icmplen < ICMP_ADVLENMIN || icmplen < ICMP_ADVLEN(icp))
1784801Swnj 			goto free;
1796583Ssam 		icmpsrc.sin_addr = ip->ip_src;
1806583Ssam 		icmpdst.sin_addr = ip->ip_dst;
1816583Ssam 		raw_input(dtom(icp), &icmproto, (struct sockaddr *)&icmpsrc,
1826583Ssam 		  (struct sockaddr *)&icmpdst);
1834785Swnj 		goto free;
1844785Swnj 
1854785Swnj 	default:
1864785Swnj 		goto free;
1874785Swnj 	}
1884785Swnj reflect:
1894785Swnj 	icmp_reflect(ip);
1909185Ssam 	return;
1914785Swnj free:
1924785Swnj 	m_freem(dtom(ip));
1934785Swnj }
1944785Swnj 
1954785Swnj /*
1964785Swnj  * Reflect the ip packet back to the source
1976583Ssam  * TODO: rearrange ip source routing options.
1984785Swnj  */
1994785Swnj icmp_reflect(ip)
2004785Swnj 	struct ip *ip;
2014785Swnj {
2024923Swnj 	struct in_addr t;
2034785Swnj 
2046583Ssam 	t = ip->ip_dst;
2056583Ssam 	ip->ip_dst = ip->ip_src;
2066583Ssam 	ip->ip_src = t;
2074785Swnj 	icmp_send(ip);
2084785Swnj }
2094785Swnj 
2104785Swnj /*
2116583Ssam  * Send an icmp packet back to the ip level,
2126583Ssam  * after supplying a checksum.
2134785Swnj  */
2144907Swnj icmp_send(ip)
2154785Swnj 	struct ip *ip;
2164785Swnj {
2179185Ssam 	register int hlen;
2186583Ssam 	register struct icmp *icp;
2199185Ssam 	register struct mbuf *m;
2206583Ssam 
2219185Ssam 	m = dtom(ip);
2229185Ssam 	hlen = ip->ip_hl << 2;
2236583Ssam 	icp = mtod(m, struct icmp *);
2246583Ssam 	icp->icmp_cksum = 0;
2256583Ssam 	icp->icmp_cksum = in_cksum(m, ip->ip_len - hlen);
2266583Ssam 	m->m_off -= hlen;
2276583Ssam 	m->m_len += hlen;
2286590Ssam 	if (icmpprintfs)
2296590Ssam 		printf("icmp_send dst %x src %x\n", ip->ip_dst, ip->ip_src);
2308637Sroot 	(void) ip_output(m, (struct mbuf *)0, (struct route *)0, 0);
2314785Swnj }
2324785Swnj 
2334907Swnj n_time
2344923Swnj iptime()
2354801Swnj {
2364907Swnj 	int s = spl6();
2374967Swnj 	u_long t;
2384801Swnj 
2398171Sroot 	t = (time.tv_sec % (24*60*60)) * 1000 + time.tv_usec / 1000;
2404907Swnj 	splx(s);
2414907Swnj 	return (htonl(t));
2424801Swnj }
243