# 2.11BSD#431 - /usr/src/sys/netinet/ip_icmp.c

##### Functions

    icmp_error        X
    icmp_input        X
    icmp_reflect      X
    icmp_send         X
    icmp_sysctl       X
    ifptoia           X
    iptime            X

##### Variables

    icmpprintfs       X

##### Macros

    satosin           X

       1: /*
       2:  * Copyright (c) 1982, 1986 Regents of the University of California.
       3:  * All rights reserved.
       4:  *
       5:  * Redistribution and use in source and binary forms are permitted
       6:  * provided that this notice is preserved and that due credit is given
       7:  * to the University of California at Berkeley. The name of the University
       8:  * may not be used to endorse or promote products derived from this
       9:  * software without specific prior written permission. This software
      10:  * is provided ``as is'' without express or implied warranty.
      11:  *
      12:  *	@(#)ip_icmp.c	7.7.2 (2.11BSD GTE) 1995/10/10
      13:  */
      14:
      15: #include "param.h"
      16: #include "systm.h"
      17: #include "mbuf.h"
      18: #include "protosw.h"
      19: #include "socket.h"
      20: #include "time.h"
      21: #include "kernel.h"
      22: #include "errno.h"
      23:
      24: #include "../net/route.h"
      25: #include "../net/if.h"
      26:
      27: #include "domain.h"
      28: #include "in.h"
      29: #include "in_systm.h"
      30: #include "in_var.h"
      31: #include "ip.h"
      32: #include "ip_icmp.h"
      33: #include "icmp_var.h"
      34:
      35: extern  int icmpmaskrepl;
      36: #ifdef ICMPPRINTFS
      37: /*
      38:  * ICMP routines: error generation, receive packet processing, and
      39:  * routines to turnaround packets back to the originator, and
      40:  * host table maintenance routines.
      41:  */
      42: int icmpprintfs = 0;
      43: #endif
      44:
      45: /*
      46:  * Generate an error packet of type error
      47:  * in response to bad packet ip.
      48:  */
      49: /*VARARGS4*/
      50: icmp_error(oip, type, code, ifp, dest)
      51:     struct ip *oip;
      52:     int type, code;
      53:     struct ifnet *ifp;
      54:     struct in_addr dest;
      55: {
      56:     register unsigned oiplen = oip->ip_hl << 2;
      57:     register struct icmp *icp;
      58:     struct mbuf *m;
      59:     struct ip *nip;
      60:     unsigned icmplen;
      61:
      62: #ifdef ICMPPRINTFS
      63:     if (icmpprintfs)
      64:         printf("icmp_error(%x, %d, %d)\n", oip, type, code);
      65: #endif
      66:     if (type != ICMP_REDIRECT)
      67:         icmpstat.icps_error++;
      68:     /*
      69: 	 * Don't send error if not the first fragment of message.
      70: 	 * Don't error if the old packet protocol was ICMP
      71: 	 * error message, only known informational types.
      72: 	 */
      73:     if (oip->ip_off &~ (IP_MF|IP_DF))
      74:         goto free;
      75:     if (oip->ip_p == IPPROTO_ICMP && type != ICMP_REDIRECT &&
      76:       !ICMP_INFOTYPE(((struct icmp *)((caddr_t)oip + oiplen))->icmp_type)) {
      77:         icmpstat.icps_oldicmp++;
      78:         goto free;
      79:     }
      80:
      81:     /*
      82: 	 * First, formulate icmp message
      83: 	 */
      84:     m = m_get(M_DONTWAIT, MT_HEADER);
      85:     if (m == NULL)
      86:         goto free;
      87:     icmplen = oiplen + MIN(8, oip->ip_len);
      88:     m->m_len = icmplen + ICMP_MINLEN;
      89:     m->m_off = MMAXOFF - m->m_len;
      90:     icp = mtod(m, struct icmp *);
      91:     if ((u_int)type > ICMP_MAXTYPE)
      92:         panic("icmp_error");
      93:     icmpstat.icps_outhist[type]++;
      94:     icp->icmp_type = type;
      95:     if (type == ICMP_REDIRECT)
      96:         icp->icmp_gwaddr = dest;
      97:     else
      98:         icp->icmp_void = 0;
      99:     if (type == ICMP_PARAMPROB) {
     100:         icp->icmp_pptr = code;
     101:         code = 0;
     102:     }
     103:     icp->icmp_code = code;
     104:     bcopy((caddr_t)oip, (caddr_t)&icp->icmp_ip, icmplen);
     105:     nip = &icp->icmp_ip;
     106:     nip->ip_len += oiplen;
     107:     nip->ip_len = htons((u_short)nip->ip_len);
     108:
     109:     /*
     110: 	 * Now, copy old ip header in front of icmp message.
     111: 	 */
     112:     if (m->m_len + oiplen > MLEN)
     113:         oiplen = sizeof(struct ip);
     114:     if (m->m_len + oiplen > MLEN)
     115:         panic("icmp len");
     116:     m->m_off -= oiplen;
     117:     m->m_len += oiplen;
     118:     nip = mtod(m, struct ip *);
     119:     bcopy((caddr_t)oip, (caddr_t)nip, oiplen);
     120:     nip->ip_len = m->m_len;
     121:     nip->ip_p = IPPROTO_ICMP;
     122:     icmp_reflect(nip, ifp);
     123:
     124: free:
     125:     m_freem(dtom(oip));
     126: }
     127:
     128: static struct sockproto icmproto = { AF_INET, IPPROTO_ICMP };
     129: static struct sockaddr_in icmpsrc = { AF_INET };
     130: static struct sockaddr_in icmpdst = { AF_INET };
     131: static struct sockaddr_in icmpgw = { AF_INET };
     132: struct in_ifaddr *ifptoia();
     133:
     134: /*
     135:  * Process a received ICMP message.
     136:  */
     137: icmp_input(m, ifp)
     138:     register struct mbuf *m;
     139:     struct ifnet *ifp;
     140: {
     141:     register struct icmp *icp;
     142:     register struct ip *ip = mtod(m, struct ip *);
     143:     int icmplen = ip->ip_len, hlen = ip->ip_hl << 2;
     144:     register int i;
     145:     struct in_ifaddr *ia;
     146:     int (*ctlfunc)(), code;
     147:     extern u_char ip_protox[];
     148:     extern struct in_addr in_makeaddr();
     149:
     150:     /*
     151: 	 * Locate icmp structure in mbuf, and check
     152: 	 * that not corrupted and of at least minimum length.
     153: 	 */
     154: #ifdef ICMPPRINTFS
     155:     if (icmpprintfs)
     156:         printf("icmp_input src %X len %d", ntohl(ip->ip_src), icmplen);
     157: #endif
     158:     if (icmplen < ICMP_MINLEN) {
     159:         icmpstat.icps_tooshort++;
     160:         goto free;
     161:     }
     162:     i = hlen + MIN(icmplen, ICMP_ADVLENMIN);
     163:     if ((m->m_off > MMAXOFF || m->m_len < i) &&
     164:         (m = m_pullup(m, i)) == 0)  {
     165:         icmpstat.icps_tooshort++;
     166:         return;
     167:     }
     168:     ip = mtod(m, struct ip *);
     169:     m->m_len -= hlen;
     170:     m->m_off += hlen;
     171:     icp = mtod(m, struct icmp *);
     172:     if (in_cksum(m, icmplen)) {
     173:         icmpstat.icps_checksum++;
     174:         goto free;
     175:     }
     176:     m->m_len += hlen;
     177:     m->m_off -= hlen;
     178:
     179: #ifdef ICMPPRINTFS
     180:     /*
     181: 	 * Message type specific processing.
     182: 	 */
     183:     if (icmpprintfs)
     184:         printf("icmp_input, type %d code %d\n", icp->icmp_type,
     185:             icp->icmp_code);
     186: #endif
     187:     if (icp->icmp_type > ICMP_MAXTYPE)
     188:         goto raw;
     189:     icmpstat.icps_inhist[icp->icmp_type]++;
     190:     code = icp->icmp_code;
     191:     switch (icp->icmp_type) {
     192:
     193:     case ICMP_UNREACH:
     194:         if (code > 5)
     195:             goto badcode;
     196:         code += PRC_UNREACH_NET;
     197:         goto deliver;
     198:
     199:     case ICMP_TIMXCEED:
     200:         if (code > 1)
     201:             goto badcode;
     202:         code += PRC_TIMXCEED_INTRANS;
     203:         goto deliver;
     204:
     205:     case ICMP_PARAMPROB:
     206:         if (code)
     207:             goto badcode;
     208:         code = PRC_PARAMPROB;
     209:         goto deliver;
     210:
     211:     case ICMP_SOURCEQUENCH:
     212:         if (code)
     213:             goto badcode;
     214:         code = PRC_QUENCH;
     215:     deliver:
     216:         /*
     217: 		 * Problem with datagram; advise higher level routines.
     218: 		 */
     219:         icp->icmp_ip.ip_len = ntohs((u_short)icp->icmp_ip.ip_len);
     220:         if (icmplen < ICMP_ADVLENMIN || icmplen < ICMP_ADVLEN(icp)) {
     221:             icmpstat.icps_badlen++;
     222:             goto free;
     223:         }
     224: #ifdef ICMPPRINTFS
     225:         if (icmpprintfs)
     226:             printf("deliver to protocol %d\n", icp->icmp_ip.ip_p);
     227: #endif
     228:         icmpsrc.sin_addr = icp->icmp_ip.ip_dst;
     229:         if (ctlfunc = inetsw[ip_protox[icp->icmp_ip.ip_p]].pr_ctlinput)
     230:             (*ctlfunc)(code, (struct sockaddr *)&icmpsrc,
     231:                 (caddr_t)&icp->icmp_ip);
     232:         break;
     233:
     234:     badcode:
     235:         icmpstat.icps_badcode++;
     236:         break;
     237:
     238:     case ICMP_ECHO:
     239:         icp->icmp_type = ICMP_ECHOREPLY;
     240:         goto reflect;
     241:
     242:     case ICMP_TSTAMP:
     243:         if (icmplen < ICMP_TSLEN) {
     244:             icmpstat.icps_badlen++;
     245:             break;
     246:         }
     247:         icp->icmp_type = ICMP_TSTAMPREPLY;
     248:         icp->icmp_rtime = iptime();
     249:         icp->icmp_ttime = icp->icmp_rtime;  /* bogus, do later! */
     250:         goto reflect;
     251:
     252:     case ICMP_IREQ:
     253: #define satosin(sa) ((struct sockaddr_in *)(sa))
     254:         if (in_netof(ip->ip_src) == 0 && (ia = ifptoia(ifp)))
     255:             ip->ip_src = in_makeaddr(in_netof(IA_SIN(ia)->sin_addr),
     256:                 in_lnaof(ip->ip_src));
     257:         icp->icmp_type = ICMP_IREQREPLY;
     258:         goto reflect;
     259:
     260:     case ICMP_MASKREQ:
     261:         if (icmpmaskrepl == 0)
     262:             break;
     263:         /*
     264: 		 * We are not able to respond with all ones broadcast
     265: 		 * unless we receive it over a point-to-point interface.
     266: 		 * This check is a 'switch' in 4.4BSD but 2.11's C compiler
     267: 		 * does not allow "long"s in a switch statement.
     268: 		*/
     269:         if (icmplen < ICMP_MASKLEN || (ia = ifptoia(ifp)) == 0)
     270:             break;
     271:         if ((ip->ip_dst.s_addr == INADDR_BROADCAST ||
     272:              ip->ip_dst.s_addr == INADDR_ANY))
     273:             icmpdst.sin_addr = ip->ip_src;
     274:         else
     275:             icmpdst.sin_addr = ip->ip_dst;
     276:         icp->icmp_type = ICMP_MASKREPLY;
     277:         icp->icmp_mask = htonl(ia->ia_subnetmask);
     278:         if (ip->ip_src.s_addr == 0) {
     279:             if (ia->ia_ifp->if_flags & IFF_BROADCAST)
     280:                 ip->ip_src = satosin(&ia->ia_broadaddr)->sin_addr;
     281:             else if (ia->ia_ifp->if_flags & IFF_POINTOPOINT)
     282:                 ip->ip_src = satosin(&ia->ia_dstaddr)->sin_addr;
     283:         }
     284: reflect:
     285:         ip->ip_len += hlen; /* since ip_input deducts this */
     286:         icmpstat.icps_reflect++;
     287:         icmpstat.icps_outhist[icp->icmp_type]++;
     288:         icmp_reflect(ip, ifp);
     289:         return;
     290:
     291:     case ICMP_REDIRECT:
     292:         if (icmplen < ICMP_ADVLENMIN || icmplen < ICMP_ADVLEN(icp)) {
     293:             icmpstat.icps_badlen++;
     294:             break;
     295:         }
     296:         /*
     297: 		 * Short circuit routing redirects to force
     298: 		 * immediate change in the kernel's routing
     299: 		 * tables.  The message is also handed to anyone
     300: 		 * listening on a raw socket (e.g. the routing
     301: 		 * daemon for use in updating its tables).
     302: 		 */
     303:         icmpgw.sin_addr = ip->ip_src;
     304:         icmpdst.sin_addr = icp->icmp_gwaddr;
     305: #ifdef  ICMPPRINTFS
     306:         if (icmpprintfs)
     307:             printf("redirect dst %X to %X\n", ntohl(icp->icmp_ip.ip_dst),
     308:                 ntohl(icp->icmp_gwaddr));
     309: #endif
     310:         if (code == ICMP_REDIRECT_NET || code == ICMP_REDIRECT_TOSNET) {
     311:             icmpsrc.sin_addr =
     312:              in_makeaddr(in_netof(icp->icmp_ip.ip_dst), INADDR_ANY);
     313:             rtredirect((struct sockaddr *)&icmpsrc,
     314:               (struct sockaddr *)&icmpdst, RTF_GATEWAY,
     315:               (struct sockaddr *)&icmpgw);
     316:             icmpsrc.sin_addr = icp->icmp_ip.ip_dst;
     317:             pfctlinput(PRC_REDIRECT_NET,
     318:               (struct sockaddr *)&icmpsrc);
     319:         } else {
     320:             icmpsrc.sin_addr = icp->icmp_ip.ip_dst;
     321:             rtredirect((struct sockaddr *)&icmpsrc,
     322:               (struct sockaddr *)&icmpdst, RTF_GATEWAY | RTF_HOST,
     323:               (struct sockaddr *)&icmpgw);
     324:             pfctlinput(PRC_REDIRECT_HOST,
     325:               (struct sockaddr *)&icmpsrc);
     326:         }
     327:         break;
     328:
     329:     /*
     330: 	 * No kernel processing for the following;
     331: 	 * just fall through to send to raw listener.
     332: 	 */
     333:     case ICMP_ECHOREPLY:
     334:     case ICMP_TSTAMPREPLY:
     335:     case ICMP_IREQREPLY:
     336:     case ICMP_MASKREPLY:
     337:     default:
     338:         break;
     339:     }
     340:
     341: raw:
     342:     icmpsrc.sin_addr = ip->ip_src;
     343:     icmpdst.sin_addr = ip->ip_dst;
     344:     raw_input(m, &icmproto, (struct sockaddr *)&icmpsrc,
     345:         (struct sockaddr *)&icmpdst);
     346:     return;
     347:
     348: free:
     349:     m_freem(m);
     350: }
     351:
     352: /*
     353:  * Reflect the ip packet back to the source
     354:  */
     355: icmp_reflect(ip, ifp)
     356:     register struct ip *ip;
     357:     struct ifnet *ifp;
     358: {
     359:     register struct in_ifaddr *ia;
     360:     struct in_addr t;
     361:     struct mbuf *opts = 0, *ip_srcroute();
     362:     int optlen = (ip->ip_hl << 2) - sizeof(struct ip);
     363:
     364:     t = ip->ip_dst;
     365:     ip->ip_dst = ip->ip_src;
     366:     /*
     367: 	 * If the incoming packet was addressed directly to us,
     368: 	 * use dst as the src for the reply.  Otherwise (broadcast
     369: 	 * or anonymous), use the address which corresponds
     370: 	 * to the incoming interface.
     371: 	 */
     372:     for (ia = in_ifaddr; ia; ia = ia->ia_next) {
     373:         if (t.s_addr == IA_SIN(ia)->sin_addr.s_addr)
     374:             break;
     375:         if ((ia->ia_ifp->if_flags & IFF_BROADCAST) &&
     376:             t.s_addr == satosin(&ia->ia_broadaddr)->sin_addr.s_addr)
     377:             break;
     378:     }
     379:     if (ia == (struct in_ifaddr *)0)
     380:         ia = ifptoia(ifp);
     381:     if (ia == (struct in_ifaddr *)0)
     382:         ia = in_ifaddr;
     383:     t = IA_SIN(ia)->sin_addr;
     384:     ip->ip_src = t;
     385:     ip->ip_ttl = MAXTTL;
     386:
     387:     if (optlen > 0) {
     388:         /*
     389: 		 * Retrieve any source routing from the incoming packet
     390: 		 * and strip out other options.  Adjust the IP length.
     391: 		 */
     392:         opts = ip_srcroute();
     393:         ip->ip_len -= optlen;
     394:         ip_stripoptions(ip, (struct mbuf *)0);
     395:     }
     396:     icmp_send(ip, opts);
     397:     if (opts)
     398:         (void)m_free(opts);
     399: }
     400:
     401: struct in_ifaddr *
     402: ifptoia(ifp)
     403:     struct ifnet *ifp;
     404: {
     405:     register struct in_ifaddr *ia;
     406:
     407:     for (ia = in_ifaddr; ia; ia = ia->ia_next)
     408:         if (ia->ia_ifp == ifp)
     409:             return (ia);
     410:     return ((struct in_ifaddr *)0);
     411: }
     412:
     413: /*
     414:  * Send an icmp packet back to the ip level,
     415:  * after supplying a checksum.
     416:  */
     417: icmp_send(ip, opts)
     418:     register struct ip *ip;
     419:     struct mbuf *opts;
     420: {
     421:     register int hlen;
     422:     register struct icmp *icp;
     423:     register struct mbuf *m;
     424:
     425:     m = dtom(ip);
     426:     hlen = ip->ip_hl << 2;
     427:     m->m_off += hlen;
     428:     m->m_len -= hlen;
     429:     icp = mtod(m, struct icmp *);
     430:     icp->icmp_cksum = 0;
     431:     icp->icmp_cksum = in_cksum(m, ip->ip_len - hlen);
     432:     m->m_off -= hlen;
     433:     m->m_len += hlen;
     434: #ifdef ICMPPRINTFS
     435:     if (icmpprintfs)
     436:         printf("icmp_send dst %X src %X\n", ntohl(ip->ip_dst.s_addr), ntohl(ip->ip_src.s_addr));
     437: #endif
     438:     (void) ip_output(m, opts, (struct route *)0, 0);
     439: }
     440:
     441: n_time
     442: iptime()
     443: {
     444:     struct timeval atv;
     445:     int s = splhigh();
     446:     u_long t;
     447:     extern struct timeval time;
     448:     extern int lbolt, hz;
     449:
     450:     cpfromkern(&time, &atv, sizeof(struct timeval));
     451:     t = (atv.tv_sec % (24L*60L*60L)) * 1000L
     452:       + (long)mfkd(&lbolt) * 1000L / (long)hz;
     453:     splx(s);
     454:     return (htonl(t));
     455: }
     456:
     457: int
     458: icmp_sysctl(name, namelen, oldp, oldlenp, newp, newlen)
     459:     int *name;
     460:     u_int namelen;
     461:     void *oldp;
     462:     size_t *oldlenp;
     463:     void *newp;
     464:     size_t newlen;
     465: {
     466:
     467:     /* All sysctl names at this level are terminal. */
     468:     if (namelen != 1)
     469:         return (ENOTDIR);
     470:
     471:     switch (name[0]) {
     472:     case ICMPCTL_MASKREPL:
     473:         return (sysctl_int(oldp, oldlenp, newp, newlen, &icmpmaskrepl));
     474:     default:
     475:         return (ENOPROTOOPT);
     476:     }
     477:     /* NOTREACHED */
     478: }

#### Defined functions

icmp_error defined in line 50; never used
icmp_input defined in line 137; never used
icmp_reflect defined in line 355; used 2 times

- in line 122, 288

icmp_send defined in line 417; used 1 times

- in line 396

icmp_sysctl defined in line 457; never used
ifptoia defined in line 401; used 4 times

- in line 132, 254, 269, 380

iptime defined in line 441; used 1 times

- in line 248

#### Defined variables

icmpdst defined in line 130; used 7 times

- in line 273-275(2), 304, 314, 322, 343-345(2)

icmpgw defined in line 131; used 3 times

- in line 303, 315, 323

icmpprintfs defined in line 42; used 6 times

- in line 63, 155, 183, 225, 306, 435

icmproto defined in line 128; used 1 times

- in line 344

icmpsrc defined in line 129; used 11 times

- in line 228-230(2), 311-325(7), 342-344(2)

#### Defined macros

satosin defined in line 253; used 3 times

- in line 280-282(2), 376

Last modified: 1995-10-11 Generated: 2016-12-26 | Generated by src2html V0.67 page hit count: 2140 |