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*57939Ssklower * @(#)ip_icmp.c 7.20 (Berkeley) 02/11/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 */ 3440684Skarels #ifdef ICMPPRINTFS 356608Ssam int icmpprintfs = 0; 3615027Smckusick #endif 374785Swnj 3848463Skarels extern struct protosw inetsw[]; 3948463Skarels 404785Swnj /* 416583Ssam * Generate an error packet of type error 426583Ssam * in response to bad packet ip. 434785Swnj */ 4440684Skarels /*VARARGS3*/ 4557433Sandrew icmp_error(n, type, code, dest, destifp) 4640684Skarels struct mbuf *n; 4712764Ssam int type, code; 4824811Skarels struct in_addr dest; 4957433Sandrew struct ifnet *destifp; 504785Swnj { 5140684Skarels register struct ip *oip = mtod(n, struct ip *), *nip; 526583Ssam register unsigned oiplen = oip->ip_hl << 2; 536583Ssam register struct icmp *icp; 5435794Skarels register struct mbuf *m; 5526383Skarels unsigned icmplen; 564785Swnj 5715027Smckusick #ifdef ICMPPRINTFS 586590Ssam if (icmpprintfs) 596590Ssam printf("icmp_error(%x, %d, %d)\n", oip, type, code); 6015027Smckusick #endif 6126034Skarels if (type != ICMP_REDIRECT) 6226034Skarels icmpstat.icps_error++; 634785Swnj /* 6424811Skarels * Don't send error if not the first fragment of message. 6531399Skarels * Don't error if the old packet protocol was ICMP 6631399Skarels * error message, only known informational types. 674785Swnj */ 6824811Skarels if (oip->ip_off &~ (IP_MF|IP_DF)) 6940684Skarels goto freeit; 7031399Skarels if (oip->ip_p == IPPROTO_ICMP && type != ICMP_REDIRECT && 7140684Skarels n->m_len >= oiplen + ICMP_MINLEN && 7231399Skarels !ICMP_INFOTYPE(((struct icmp *)((caddr_t)oip + oiplen))->icmp_type)) { 7311532Ssam icmpstat.icps_oldicmp++; 7440684Skarels goto freeit; 7511532Ssam } 7654716Ssklower /* Don't send error in response to a multicast or broadcast packet */ 7757433Sandrew if ((n->m_flags & (M_BCAST|M_MCAST)) || 7857433Sandrew in_broadcast(oip->ip_dst) || 7957433Sandrew IN_MULTICAST(ntohl(oip->ip_dst.s_addr)) || 8057433Sandrew IN_EXPERIMENTAL(ntohl(oip->ip_dst.s_addr))) 8154716Ssklower goto freeit; 824785Swnj /* 836583Ssam * First, formulate icmp message 844785Swnj */ 8540684Skarels m = m_gethdr(M_DONTWAIT, MT_HEADER); 8611532Ssam if (m == NULL) 8740684Skarels goto freeit; 8835794Skarels icmplen = oiplen + min(8, oip->ip_len); 8924811Skarels m->m_len = icmplen + ICMP_MINLEN; 9040684Skarels MH_ALIGN(m, m->m_len); 916583Ssam icp = mtod(m, struct icmp *); 9224811Skarels if ((u_int)type > ICMP_MAXTYPE) 9311532Ssam panic("icmp_error"); 9411532Ssam icmpstat.icps_outhist[type]++; 954785Swnj icp->icmp_type = type; 9624811Skarels if (type == ICMP_REDIRECT) 9724811Skarels icp->icmp_gwaddr = dest; 9857433Sandrew else { 9924811Skarels icp->icmp_void = 0; 10057433Sandrew /* 10157433Sandrew * The following assignments assume an overlay with the 10257433Sandrew * zeroed icmp_void field. 10357433Sandrew */ 10457433Sandrew if (type == ICMP_PARAMPROB) { 10557433Sandrew icp->icmp_pptr = code; 10657433Sandrew code = 0; 10757433Sandrew } else if (type == ICMP_UNREACH && 10857433Sandrew code == ICMP_UNREACH_NEEDFRAG && destifp) { 10957433Sandrew icp->icmp_nextmtu = htons(destifp->if_mtu); 11057433Sandrew } 1116583Ssam } 11257433Sandrew 1136583Ssam icp->icmp_code = code; 11424811Skarels bcopy((caddr_t)oip, (caddr_t)&icp->icmp_ip, icmplen); 1156590Ssam nip = &icp->icmp_ip; 11635794Skarels nip->ip_len = htons((u_short)(nip->ip_len + oiplen)); 1174785Swnj 1184785Swnj /* 11936817Skarels * Now, copy old ip header (without options) 12036817Skarels * in front of icmp message. 1214785Swnj */ 12240684Skarels if (m->m_data - sizeof(struct ip) < m->m_pktdat) 12324811Skarels panic("icmp len"); 12440684Skarels m->m_data -= sizeof(struct ip); 12536817Skarels m->m_len += sizeof(struct ip); 12640684Skarels m->m_pkthdr.len = m->m_len; 12740684Skarels m->m_pkthdr.rcvif = n->m_pkthdr.rcvif; 1286583Ssam nip = mtod(m, struct ip *); 12957433Sandrew bcopy((caddr_t)oip, (caddr_t)nip, sizeof(struct ip)); 13027063Skarels nip->ip_len = m->m_len; 13136817Skarels nip->ip_hl = sizeof(struct ip) >> 2; 1326583Ssam nip->ip_p = IPPROTO_ICMP; 13357433Sandrew nip->ip_tos = 0; 13440684Skarels icmp_reflect(m); 1354785Swnj 13640684Skarels freeit: 13740684Skarels m_freem(n); 1384785Swnj } 1394785Swnj 1406583Ssam static struct sockproto icmproto = { AF_INET, IPPROTO_ICMP }; 14140684Skarels static struct sockaddr_in icmpsrc = { sizeof (struct sockaddr_in), AF_INET }; 14240684Skarels static struct sockaddr_in icmpdst = { sizeof (struct sockaddr_in), AF_INET }; 14340684Skarels static struct sockaddr_in icmpgw = { sizeof (struct sockaddr_in), AF_INET }; 14440684Skarels struct sockaddr_in icmpmask = { 8, 0 }; 14524811Skarels struct in_ifaddr *ifptoia(); 1466583Ssam 1474785Swnj /* 1484801Swnj * Process a received ICMP message. 1494785Swnj */ 15040684Skarels icmp_input(m, hlen) 15127194Skarels register struct mbuf *m; 15240684Skarels int hlen; 1534785Swnj { 1544801Swnj register struct icmp *icp; 1554801Swnj register struct ip *ip = mtod(m, struct ip *); 15640684Skarels int icmplen = ip->ip_len; 15716171Skarels register int i; 15824811Skarels struct in_ifaddr *ia; 15916171Skarels int (*ctlfunc)(), code; 1605172Swnj extern u_char ip_protox[]; 16118373Skarels extern struct in_addr in_makeaddr(); 1624785Swnj 1634785Swnj /* 1644785Swnj * Locate icmp structure in mbuf, and check 1654785Swnj * that not corrupted and of at least minimum length. 1664785Swnj */ 16715027Smckusick #ifdef ICMPPRINTFS 1686590Ssam if (icmpprintfs) 1696590Ssam printf("icmp_input from %x, len %d\n", ip->ip_src, 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 2914785Swnj case ICMP_IREQ: 29218373Skarels #define satosin(sa) ((struct sockaddr_in *)(sa)) 29340684Skarels if (in_netof(ip->ip_src) == 0 && 29440684Skarels (ia = ifptoia(m->m_pkthdr.rcvif))) 29524811Skarels ip->ip_src = in_makeaddr(in_netof(IA_SIN(ia)->sin_addr), 29618373Skarels in_lnaof(ip->ip_src)); 29718373Skarels icp->icmp_type = ICMP_IREQREPLY; 2984785Swnj goto reflect; 2994785Swnj 30024811Skarels case ICMP_MASKREQ: 30140684Skarels if (icmplen < ICMP_MASKLEN || 30254716Ssklower m->m_flags & M_BCAST || /* Don't reply to broadcasts */ 30340684Skarels (ia = ifptoia(m->m_pkthdr.rcvif)) == 0) 30427063Skarels break; 30530362Skarels icp->icmp_type = ICMP_MASKREPLY; 30640684Skarels icp->icmp_mask = ia->ia_sockmask.sin_addr.s_addr; 30724811Skarels if (ip->ip_src.s_addr == 0) { 30824811Skarels if (ia->ia_ifp->if_flags & IFF_BROADCAST) 30924811Skarels ip->ip_src = satosin(&ia->ia_broadaddr)->sin_addr; 31024811Skarels else if (ia->ia_ifp->if_flags & IFF_POINTOPOINT) 31124811Skarels ip->ip_src = satosin(&ia->ia_dstaddr)->sin_addr; 31224811Skarels } 31327063Skarels reflect: 31427063Skarels ip->ip_len += hlen; /* since ip_input deducts this */ 31527063Skarels icmpstat.icps_reflect++; 31627063Skarels icmpstat.icps_outhist[icp->icmp_type]++; 31740684Skarels icmp_reflect(m); 31827063Skarels return; 31924811Skarels 32011549Ssam case ICMP_REDIRECT: 32157433Sandrew if (code > 3) 32257433Sandrew goto badcode; 32357433Sandrew if (icmplen < ICMP_ADVLENMIN || icmplen < ICMP_ADVLEN(icp) || 32457433Sandrew icp->icmp_ip.ip_hl < (sizeof(struct ip) >> 2)) { 32557433Sandrew icmpstat.icps_badlen++; 32657433Sandrew break; 32757433Sandrew } 32811532Ssam if (icmplen < ICMP_ADVLENMIN || icmplen < ICMP_ADVLEN(icp)) { 32911532Ssam icmpstat.icps_badlen++; 33027063Skarels break; 33111532Ssam } 33211549Ssam /* 33311549Ssam * Short circuit routing redirects to force 33411549Ssam * immediate change in the kernel's routing 33511549Ssam * tables. The message is also handed to anyone 33611549Ssam * listening on a raw socket (e.g. the routing 33717046Skarels * daemon for use in updating its tables). 33811549Ssam */ 33924811Skarels icmpgw.sin_addr = ip->ip_src; 34015831Skarels icmpdst.sin_addr = icp->icmp_gwaddr; 34124811Skarels #ifdef ICMPPRINTFS 34224811Skarels if (icmpprintfs) 34324811Skarels printf("redirect dst %x to %x\n", icp->icmp_ip.ip_dst, 34424811Skarels icp->icmp_gwaddr); 34524811Skarels #endif 34617046Skarels if (code == ICMP_REDIRECT_NET || code == ICMP_REDIRECT_TOSNET) { 34740684Skarels u_long in_netof(); 34817046Skarels icmpsrc.sin_addr = 34918373Skarels in_makeaddr(in_netof(icp->icmp_ip.ip_dst), INADDR_ANY); 35040684Skarels in_sockmaskof(icp->icmp_ip.ip_dst, &icmpmask); 35117046Skarels rtredirect((struct sockaddr *)&icmpsrc, 35240684Skarels (struct sockaddr *)&icmpdst, 35340684Skarels (struct sockaddr *)&icmpmask, RTF_GATEWAY, 35440684Skarels (struct sockaddr *)&icmpgw, (struct rtentry **)0); 35527194Skarels icmpsrc.sin_addr = icp->icmp_ip.ip_dst; 35624811Skarels pfctlinput(PRC_REDIRECT_NET, 35724811Skarels (struct sockaddr *)&icmpsrc); 35817046Skarels } else { 35917046Skarels icmpsrc.sin_addr = icp->icmp_ip.ip_dst; 36017046Skarels rtredirect((struct sockaddr *)&icmpsrc, 36140684Skarels (struct sockaddr *)&icmpdst, 36240684Skarels (struct sockaddr *)0, RTF_GATEWAY | RTF_HOST, 36340684Skarels (struct sockaddr *)&icmpgw, (struct rtentry **)0); 36424811Skarels pfctlinput(PRC_REDIRECT_HOST, 36524811Skarels (struct sockaddr *)&icmpsrc); 36617046Skarels } 36727063Skarels break; 36815831Skarels 36927063Skarels /* 37027063Skarels * No kernel processing for the following; 37127063Skarels * just fall through to send to raw listener. 37227063Skarels */ 37315831Skarels case ICMP_ECHOREPLY: 37457433Sandrew case ICMP_ROUTERADVERT: 37557433Sandrew case ICMP_ROUTERSOLICIT: 37615831Skarels case ICMP_TSTAMPREPLY: 37715831Skarels case ICMP_IREQREPLY: 37824811Skarels case ICMP_MASKREPLY: 3794785Swnj default: 38027063Skarels break; 3814785Swnj } 38227063Skarels 38327194Skarels raw: 38454716Ssklower rip_input(m); 3859185Ssam return; 38627063Skarels 38740684Skarels freeit: 38827063Skarels m_freem(m); 3894785Swnj } 3904785Swnj 3914785Swnj /* 3924785Swnj * Reflect the ip packet back to the source 3934785Swnj */ 39440684Skarels icmp_reflect(m) 39540684Skarels struct mbuf *m; 3964785Swnj { 39740684Skarels register struct ip *ip = mtod(m, struct ip *); 39818373Skarels register struct in_ifaddr *ia; 39924811Skarels struct in_addr t; 40028926Skarels struct mbuf *opts = 0, *ip_srcroute(); 40127063Skarels int optlen = (ip->ip_hl << 2) - sizeof(struct ip); 4024785Swnj 4036583Ssam t = ip->ip_dst; 40424811Skarels ip->ip_dst = ip->ip_src; 40524811Skarels /* 40624811Skarels * If the incoming packet was addressed directly to us, 40724811Skarels * use dst as the src for the reply. Otherwise (broadcast 40824811Skarels * or anonymous), use the address which corresponds 40924811Skarels * to the incoming interface. 41024811Skarels */ 41124811Skarels for (ia = in_ifaddr; ia; ia = ia->ia_next) { 41224811Skarels if (t.s_addr == IA_SIN(ia)->sin_addr.s_addr) 41318373Skarels break; 41424811Skarels if ((ia->ia_ifp->if_flags & IFF_BROADCAST) && 41524811Skarels t.s_addr == satosin(&ia->ia_broadaddr)->sin_addr.s_addr) 41624811Skarels break; 41724811Skarels } 41824811Skarels if (ia == (struct in_ifaddr *)0) 41940684Skarels ia = ifptoia(m->m_pkthdr.rcvif); 42028344Skarels if (ia == (struct in_ifaddr *)0) 42128344Skarels ia = in_ifaddr; 42228344Skarels t = IA_SIN(ia)->sin_addr; 42324811Skarels ip->ip_src = t; 42430971Skarels ip->ip_ttl = MAXTTL; 42524811Skarels 42627063Skarels if (optlen > 0) { 42736817Skarels register u_char *cp; 42840684Skarels int opt, cnt; 42936817Skarels u_int len; 43036817Skarels 43126034Skarels /* 43236817Skarels * Retrieve any source routing from the incoming packet; 43336817Skarels * add on any record-route or timestamp options. 43426034Skarels */ 43536817Skarels cp = (u_char *) (ip + 1); 43636948Skarels if ((opts = ip_srcroute()) == 0 && 43740684Skarels (opts = m_gethdr(M_DONTWAIT, MT_HEADER))) { 43836948Skarels opts->m_len = sizeof(struct in_addr); 43936948Skarels mtod(opts, struct in_addr *)->s_addr = 0; 44036948Skarels } 44136948Skarels if (opts) { 44236948Skarels #ifdef ICMPPRINTFS 44336948Skarels if (icmpprintfs) 44436948Skarels printf("icmp_reflect optlen %d rt %d => ", 44536948Skarels optlen, opts->m_len); 44636948Skarels #endif 44736817Skarels for (cnt = optlen; cnt > 0; cnt -= len, cp += len) { 44836948Skarels opt = cp[IPOPT_OPTVAL]; 44936948Skarels if (opt == IPOPT_EOL) 45036948Skarels break; 45136948Skarels if (opt == IPOPT_NOP) 45236948Skarels len = 1; 45336948Skarels else { 45436948Skarels len = cp[IPOPT_OLEN]; 45536948Skarels if (len <= 0 || len > cnt) 45636948Skarels break; 45736948Skarels } 45836948Skarels /* 45957433Sandrew * Should check for overflow, but it "can't happen" 46036948Skarels */ 46157433Sandrew if (opt == IPOPT_RR || opt == IPOPT_TS || 46257433Sandrew opt == IPOPT_SECURITY) { 46336948Skarels bcopy((caddr_t)cp, 46436948Skarels mtod(opts, caddr_t) + opts->m_len, len); 46536948Skarels opts->m_len += len; 46636948Skarels } 46736948Skarels } 46857433Sandrew /* Terminate & pad, if necessary */ 46957433Sandrew if (cnt = opts->m_len % 4) { 47057433Sandrew for (; cnt < 4; cnt++) { 47157433Sandrew *(mtod(opts, caddr_t) + opts->m_len) = 47257433Sandrew IPOPT_EOL; 47357433Sandrew opts->m_len++; 47457433Sandrew } 47536948Skarels } 47636948Skarels #ifdef ICMPPRINTFS 47736948Skarels if (icmpprintfs) 47836948Skarels printf("%d\n", opts->m_len); 47936948Skarels #endif 48036817Skarels } 48136948Skarels /* 48236948Skarels * Now strip out original options by copying rest of first 48336948Skarels * mbuf's data back, and adjust the IP length. 48436948Skarels */ 48526034Skarels ip->ip_len -= optlen; 48636817Skarels ip->ip_hl = sizeof(struct ip) >> 2; 48736948Skarels m->m_len -= optlen; 48840684Skarels if (m->m_flags & M_PKTHDR) 48940684Skarels m->m_pkthdr.len -= optlen; 49036948Skarels optlen += sizeof(struct ip); 49136948Skarels bcopy((caddr_t)ip + optlen, (caddr_t)(ip + 1), 49240684Skarels (unsigned)(m->m_len - sizeof(struct ip))); 49324811Skarels } 494*57939Ssklower m->m_flags &= ~(M_BCAST|M_MCAST); 49540684Skarels icmp_send(m, opts); 49626034Skarels if (opts) 49726383Skarels (void)m_free(opts); 4984785Swnj } 4994785Swnj 50024811Skarels struct in_ifaddr * 50124811Skarels ifptoia(ifp) 50224811Skarels struct ifnet *ifp; 50324811Skarels { 50424811Skarels register struct in_ifaddr *ia; 50524811Skarels 50624811Skarels for (ia = in_ifaddr; ia; ia = ia->ia_next) 50724811Skarels if (ia->ia_ifp == ifp) 50824811Skarels return (ia); 50924811Skarels return ((struct in_ifaddr *)0); 51024811Skarels } 51124811Skarels 5124785Swnj /* 5136583Ssam * Send an icmp packet back to the ip level, 5146583Ssam * after supplying a checksum. 5154785Swnj */ 51640684Skarels icmp_send(m, opts) 51740684Skarels register struct mbuf *m; 51826034Skarels struct mbuf *opts; 5194785Swnj { 52040684Skarels register struct ip *ip = mtod(m, struct ip *); 5219185Ssam register int hlen; 5226583Ssam register struct icmp *icp; 5236583Ssam 5249185Ssam hlen = ip->ip_hl << 2; 52540684Skarels m->m_data += hlen; 52627063Skarels m->m_len -= hlen; 5276583Ssam icp = mtod(m, struct icmp *); 5286583Ssam icp->icmp_cksum = 0; 5296583Ssam icp->icmp_cksum = in_cksum(m, ip->ip_len - hlen); 53040684Skarels m->m_data -= hlen; 5316583Ssam m->m_len += hlen; 53215027Smckusick #ifdef ICMPPRINTFS 5336590Ssam if (icmpprintfs) 5346590Ssam printf("icmp_send dst %x src %x\n", ip->ip_dst, ip->ip_src); 53515027Smckusick #endif 53626034Skarels (void) ip_output(m, opts, (struct route *)0, 0); 5374785Swnj } 5384785Swnj 5394907Swnj n_time 5404923Swnj iptime() 5414801Swnj { 54225893Skarels struct timeval atv; 5434967Swnj u_long t; 5444801Swnj 54525893Skarels microtime(&atv); 54625893Skarels t = (atv.tv_sec % (24*60*60)) * 1000 + atv.tv_usec / 1000; 5474907Swnj return (htonl(t)); 5484801Swnj } 549