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