123182Smckusick /* 254716Ssklower * Copyright (c) 1982, 1986, 1988 Regents of the University of California. 332787Sbostic * All rights reserved. 423182Smckusick * 544478Sbostic * %sccs.include.redist.c% 632787Sbostic * 7*59135Smckusick * @(#)ip_icmp.c 7.22 (Berkeley) 04/18/93 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 1956531Sbostic #include <net/route.h> 2056531Sbostic #include <net/if.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 */ 34*59135Smckusick 35*59135Smckusick 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 */ 4640684Skarels /*VARARGS3*/ 4757433Sandrew icmp_error(n, type, code, dest, destifp) 4840684Skarels struct mbuf *n; 4912764Ssam int type, code; 5024811Skarels struct in_addr 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) 9624811Skarels icp->icmp_gwaddr = 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 1396583Ssam static struct sockproto icmproto = { AF_INET, IPPROTO_ICMP }; 14040684Skarels static struct sockaddr_in icmpsrc = { sizeof (struct sockaddr_in), AF_INET }; 14140684Skarels static struct sockaddr_in icmpdst = { sizeof (struct sockaddr_in), AF_INET }; 14240684Skarels static struct sockaddr_in icmpgw = { sizeof (struct sockaddr_in), AF_INET }; 14340684Skarels struct sockaddr_in icmpmask = { 8, 0 }; 14424811Skarels struct in_ifaddr *ifptoia(); 1456583Ssam 1464785Swnj /* 1474801Swnj * Process a received ICMP message. 1484785Swnj */ 14940684Skarels icmp_input(m, hlen) 15027194Skarels register struct mbuf *m; 15140684Skarels int hlen; 1524785Swnj { 1534801Swnj register struct icmp *icp; 1544801Swnj register struct ip *ip = mtod(m, struct ip *); 15540684Skarels int icmplen = ip->ip_len; 15616171Skarels register int i; 15724811Skarels struct in_ifaddr *ia; 15816171Skarels int (*ctlfunc)(), 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, 27040684Skarels (caddr_t) &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)) 293*59135Smckusick if (icmpmaskrepl == 0) 294*59135Smckusick 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 */ 38540684Skarels icmp_reflect(m) 38640684Skarels struct mbuf *m; 3874785Swnj { 38840684Skarels register struct ip *ip = mtod(m, struct ip *); 38918373Skarels register struct in_ifaddr *ia; 39024811Skarels struct in_addr t; 39128926Skarels struct mbuf *opts = 0, *ip_srcroute(); 39227063Skarels int optlen = (ip->ip_hl << 2) - sizeof(struct ip); 3934785Swnj 39458998Ssklower if (!in_canforward(ip->ip_src) && 39558998Ssklower ((ntohl(ip->ip_src.s_addr) & IN_CLASSA_NET) != 39658998Ssklower (IN_LOOPBACKNET << IN_CLASSA_NSHIFT))) { 39758998Ssklower m_freem(m); /* Bad return address */ 39858998Ssklower goto done; /* Ip_output() will check for broadcast */ 39958998Ssklower } 4006583Ssam t = ip->ip_dst; 40124811Skarels ip->ip_dst = ip->ip_src; 40224811Skarels /* 40324811Skarels * If the incoming packet was addressed directly to us, 40424811Skarels * use dst as the src for the reply. Otherwise (broadcast 40524811Skarels * or anonymous), use the address which corresponds 40624811Skarels * to the incoming interface. 40724811Skarels */ 40824811Skarels for (ia = in_ifaddr; ia; ia = ia->ia_next) { 40924811Skarels if (t.s_addr == IA_SIN(ia)->sin_addr.s_addr) 41018373Skarels break; 41124811Skarels if ((ia->ia_ifp->if_flags & IFF_BROADCAST) && 41224811Skarels t.s_addr == satosin(&ia->ia_broadaddr)->sin_addr.s_addr) 41324811Skarels break; 41424811Skarels } 41558998Ssklower icmpdst.sin_addr = t; 41624811Skarels if (ia == (struct in_ifaddr *)0) 41758998Ssklower ia = (struct in_ifaddr *)ifaof_ifpforaddr( 41858998Ssklower (struct sockaddr *)&icmpdst, m->m_pkthdr.rcvif); 41958998Ssklower /* 42058998Ssklower * The following happens if the packet was not addressed to us, 42158998Ssklower * and was received on an interface with no IP address. 42258998Ssklower */ 42328344Skarels if (ia == (struct in_ifaddr *)0) 42428344Skarels ia = in_ifaddr; 42528344Skarels t = IA_SIN(ia)->sin_addr; 42624811Skarels ip->ip_src = t; 42730971Skarels ip->ip_ttl = MAXTTL; 42824811Skarels 42927063Skarels if (optlen > 0) { 43036817Skarels register u_char *cp; 43140684Skarels int opt, cnt; 43236817Skarels u_int len; 43336817Skarels 43426034Skarels /* 43536817Skarels * Retrieve any source routing from the incoming packet; 43636817Skarels * add on any record-route or timestamp options. 43726034Skarels */ 43836817Skarels cp = (u_char *) (ip + 1); 43936948Skarels if ((opts = ip_srcroute()) == 0 && 44040684Skarels (opts = m_gethdr(M_DONTWAIT, MT_HEADER))) { 44136948Skarels opts->m_len = sizeof(struct in_addr); 44236948Skarels mtod(opts, struct in_addr *)->s_addr = 0; 44336948Skarels } 44436948Skarels if (opts) { 44536948Skarels #ifdef ICMPPRINTFS 44636948Skarels if (icmpprintfs) 44736948Skarels printf("icmp_reflect optlen %d rt %d => ", 44836948Skarels optlen, opts->m_len); 44936948Skarels #endif 45036817Skarels for (cnt = optlen; cnt > 0; cnt -= len, cp += len) { 45136948Skarels opt = cp[IPOPT_OPTVAL]; 45236948Skarels if (opt == IPOPT_EOL) 45336948Skarels break; 45436948Skarels if (opt == IPOPT_NOP) 45536948Skarels len = 1; 45636948Skarels else { 45736948Skarels len = cp[IPOPT_OLEN]; 45836948Skarels if (len <= 0 || len > cnt) 45936948Skarels break; 46036948Skarels } 46136948Skarels /* 46257433Sandrew * Should check for overflow, but it "can't happen" 46336948Skarels */ 46457433Sandrew if (opt == IPOPT_RR || opt == IPOPT_TS || 46557433Sandrew opt == IPOPT_SECURITY) { 46636948Skarels bcopy((caddr_t)cp, 46736948Skarels mtod(opts, caddr_t) + opts->m_len, len); 46836948Skarels opts->m_len += len; 46936948Skarels } 47036948Skarels } 47157433Sandrew /* Terminate & pad, if necessary */ 47257433Sandrew if (cnt = opts->m_len % 4) { 47357433Sandrew for (; cnt < 4; cnt++) { 47457433Sandrew *(mtod(opts, caddr_t) + opts->m_len) = 47557433Sandrew IPOPT_EOL; 47657433Sandrew opts->m_len++; 47757433Sandrew } 47836948Skarels } 47936948Skarels #ifdef ICMPPRINTFS 48036948Skarels if (icmpprintfs) 48136948Skarels printf("%d\n", opts->m_len); 48236948Skarels #endif 48336817Skarels } 48436948Skarels /* 48536948Skarels * Now strip out original options by copying rest of first 48636948Skarels * mbuf's data back, and adjust the IP length. 48736948Skarels */ 48826034Skarels ip->ip_len -= optlen; 48936817Skarels ip->ip_hl = sizeof(struct ip) >> 2; 49036948Skarels m->m_len -= optlen; 49140684Skarels if (m->m_flags & M_PKTHDR) 49240684Skarels m->m_pkthdr.len -= optlen; 49336948Skarels optlen += sizeof(struct ip); 49436948Skarels bcopy((caddr_t)ip + optlen, (caddr_t)(ip + 1), 49540684Skarels (unsigned)(m->m_len - sizeof(struct ip))); 49624811Skarels } 49757939Ssklower m->m_flags &= ~(M_BCAST|M_MCAST); 49840684Skarels icmp_send(m, opts); 49958998Ssklower done: 50026034Skarels if (opts) 50126383Skarels (void)m_free(opts); 5024785Swnj } 5034785Swnj 5044785Swnj /* 5056583Ssam * Send an icmp packet back to the ip level, 5066583Ssam * after supplying a checksum. 5074785Swnj */ 50840684Skarels icmp_send(m, opts) 50940684Skarels register struct mbuf *m; 51026034Skarels struct mbuf *opts; 5114785Swnj { 51240684Skarels register struct ip *ip = mtod(m, struct ip *); 5139185Ssam register int hlen; 5146583Ssam register struct icmp *icp; 5156583Ssam 5169185Ssam hlen = ip->ip_hl << 2; 51740684Skarels m->m_data += hlen; 51827063Skarels m->m_len -= hlen; 5196583Ssam icp = mtod(m, struct icmp *); 5206583Ssam icp->icmp_cksum = 0; 5216583Ssam icp->icmp_cksum = in_cksum(m, ip->ip_len - hlen); 52240684Skarels m->m_data -= hlen; 5236583Ssam m->m_len += hlen; 52415027Smckusick #ifdef ICMPPRINTFS 5256590Ssam if (icmpprintfs) 5266590Ssam printf("icmp_send dst %x src %x\n", ip->ip_dst, ip->ip_src); 52715027Smckusick #endif 52826034Skarels (void) ip_output(m, opts, (struct route *)0, 0); 5294785Swnj } 5304785Swnj 5314907Swnj n_time 5324923Swnj iptime() 5334801Swnj { 53425893Skarels struct timeval atv; 5354967Swnj u_long t; 5364801Swnj 53725893Skarels microtime(&atv); 53825893Skarels t = (atv.tv_sec % (24*60*60)) * 1000 + atv.tv_usec / 1000; 5394907Swnj return (htonl(t)); 5404801Swnj } 541*59135Smckusick 542*59135Smckusick icmp_sysctl(name, namelen, oldp, oldlenp, newp, newlen) 543*59135Smckusick int *name; 544*59135Smckusick u_int namelen; 545*59135Smckusick void *oldp; 546*59135Smckusick size_t *oldlenp; 547*59135Smckusick void *newp; 548*59135Smckusick size_t newlen; 549*59135Smckusick { 550*59135Smckusick extern int ip_ttl; 551*59135Smckusick 552*59135Smckusick /* all sysctl names at this level are terminal */ 553*59135Smckusick if (namelen != 1) 554*59135Smckusick return (ENOTDIR); 555*59135Smckusick 556*59135Smckusick switch (name[0]) { 557*59135Smckusick case ICMPCTL_MASKREPL: 558*59135Smckusick return (sysctl_int(oldp, oldlenp, newp, newlen, &icmpmaskrepl)); 559*59135Smckusick default: 560*59135Smckusick return (ENOPROTOOPT); 561*59135Smckusick } 562*59135Smckusick /* NOTREACHED */ 563*59135Smckusick } 564