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

Defined functions

icmp_input defined in line 127; used 2 times
icmp_reflect defined in line 331; used 2 times
icmp_send defined in line 392; used 1 times
ifptoia defined in line 376; used 6 times

Defined variables

icmpdst defined in line 120; used 5 times
icmpgw defined in line 121; used 3 times
icmpprintfs defined in line 33; used 6 times
icmproto defined in line 118; used 1 times
icmpsrc defined in line 119; used 11 times

Defined macros

satosin defined in line 242; used 3 times
Last modified: 1986-06-05
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 1729
Valid CSS Valid XHTML 1.0 Strict