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