home *** CD-ROM | disk | FTP | other *** search
/ The Datafile PD-CD 5 / DATAFILE_PDCD5.iso / internet / netlite2 / NET / c / ICMP < prev    next >
Encoding:
Text File  |  1993-04-11  |  6.1 KB  |  186 lines

  1. /* Internet Control Message Protocol */
  2. #include "global.h"
  3. #include "mbuf.h"
  4. #include "misc.h"
  5. #include "internet.h"
  6. #include "timer.h"
  7. #include "iface.h"
  8. #include "ip.h"
  9. #include "netuser.h"
  10. #include "tcp.h"
  11. #include "icmp.h"
  12.  
  13. struct icmp_errors icmp_errors;
  14. struct icmp_stats icmp_stats;
  15.  
  16. /* Process an incoming ICMP packet */
  17. void icmp_input(struct mbuf *bp, char protocol, int32 source,
  18.                 int32 dest, char tos, int16 length, char rxbroadcast)
  19. {
  20.         struct mbuf *tbp;
  21.         struct icmp icmp;       /* ICMP header */
  22.         struct ip ip;           /* Offending datagram header */
  23.         int16 type;             /* Type of ICMP message */
  24.  
  25.         protocol = protocol;
  26.  
  27.         if(rxbroadcast){
  28.                 /* Broadcast ICMP packets are to be IGNORED !! */
  29.                 icmp_errors.bdcsts++;
  30.                 free_p(bp);
  31.                 return;
  32.         }
  33.         if(cksum(NULLHEADER,bp,length) != 0){
  34.                 /* Bad ICMP checksum; discard */
  35.                 icmp_errors.checksum++;
  36.                 free_p(bp);
  37.                 return;
  38.         }
  39.         ntohicmp(&icmp,&bp);
  40.  
  41.         /* Process the message. Some messages are passed up to the protocol
  42.          * module for handling, others are handled here.
  43.          */
  44.         type = icmp.type;
  45.         if(type < ICMP_TYPES)
  46.                 icmp_stats.input[type]++;
  47.  
  48.         switch(uchar(type)){
  49.         case TIME_EXCEED:       /* Time-to-live Exceeded */
  50.         case DEST_UNREACH:      /* Destination Unreachable */
  51.         case QUENCH:            /* Source Quench */
  52.                 ntohip(&ip,&bp);        /* Extract offending IP header */
  53.                 switch(uchar(ip.protocol)){
  54.                 case TCP_PTCL:
  55.                         tcp_icmp(ip.source,ip.dest,icmp.type,icmp.code,&bp);
  56.                         break;
  57.                 }
  58.                 break;
  59.         case ECHO:              /* Echo Request */
  60.                 /* Change type to ECHO_REPLY, recompute checksum,
  61.                  * and return datagram.
  62.                  */
  63.                 icmp.type = ECHO_REPLY;
  64.                 if((tbp = htonicmp(&icmp,bp)) == NULLBUF){
  65.                         free_p(bp);
  66.                         return;
  67.                 }
  68.                 icmp_stats.output[ECHO_REPLY]++;
  69.                 ip_send(dest,source,ICMP_PTCL,tos,0,tbp,length,0,0);
  70.                 return;
  71.         case REDIRECT:          /* Redirect */
  72.         case PARAM_PROB:        /* Parameter Problem */
  73.                 break;
  74.        case ECHO_REPLY:         /* Echo Reply */
  75.                 echo_proc(source,dest,&icmp,bp);
  76.                 break;
  77.         case TIMESTAMP:         /* Timestamp */
  78.         case TIME_REPLY:        /* Timestamp Reply */
  79.         case INFO_RQST:         /* Information Request */
  80.         case INFO_REPLY:        /* Information Reply */
  81.                 break;
  82.         }
  83.         free_p(bp);
  84. }
  85. /* Return an ICMP response to the sender of a datagram.
  86.  * Unlike most routines, the callER frees the mbuf.
  87.  */
  88. int icmp_output(struct ip *ip, struct mbuf *data, char type, char code,
  89.                 union icmp_args *args)
  90. {
  91.         struct mbuf *bp;
  92.         struct icmp icmp;       /* ICMP protocol header */
  93.         int16 dlen;             /* Length of data portion of offending pkt */
  94.         int16 length;           /* Total length of reply */
  95.         extern int32 ip_addr;   /* Our IP address */
  96.  
  97.         if(ip == NULLIP)
  98.                 return -1;
  99.         if(type < ICMP_TYPES)
  100.                 icmp_stats.output[type]++;
  101.  
  102.         if(uchar(ip->protocol) == ICMP_PTCL){
  103.                 /* Never send an ICMP message about another ICMP message */
  104.                 icmp_errors.noloop++;
  105.                 return -1;
  106.         }
  107.         /* Compute amount of original datagram to return.
  108.          * We return the original IP header, and up to 8 bytes past that.
  109.          */
  110.         dlen = min(8,len_mbuf(data));
  111.         length = dlen + ICMPLEN + IPLEN + ip->optlen;
  112.         /* Take excerpt from data portion */
  113.         if(data != NULLBUF && (bp = copy_p(data,dlen)) == NULLBUF)
  114.                 return -1;      /* The caller will free data */
  115.  
  116.         /* Recreate and tack on offending IP header */
  117.         if((data = htonip(ip,bp)) == NULLBUF){
  118.                 free_p(bp);
  119.                 return -1;
  120.         }
  121.         icmp.type = type;
  122.         icmp.code = code;
  123.         switch(uchar(icmp.type)){
  124.         case PARAM_PROB:
  125.                 icmp.args.pointer = args->pointer;
  126.                 break;
  127.         case REDIRECT:
  128.                 icmp.args.address = args->address;
  129.                 break;
  130.         case ECHO:
  131.         case ECHO_REPLY:
  132.         case INFO_RQST:
  133.         case INFO_REPLY:
  134.         case TIMESTAMP:
  135.         case TIME_REPLY:
  136.                 icmp.args.echo.id = args->echo.id;
  137.                 icmp.args.echo.seq = args->echo.seq;
  138.                 break;
  139.         default:
  140.                 icmp.args.unused = 0;
  141.                 break;
  142.         }
  143.         /* Now stick on the ICMP header */
  144.         if((bp = htonicmp(&icmp,data)) == NULLBUF){
  145.                 free_p(data);
  146.                 return -1;
  147.         }
  148.         return ip_send(ip_addr,ip->source,ICMP_PTCL,ip->tos,0,bp,length,0,0);
  149. }
  150. /* Generate ICMP header in network byte order, link data, compute checksum */
  151. struct mbuf *htonicmp(struct icmp *icmp, struct mbuf *data)
  152. {
  153.         struct mbuf *bp;
  154.         register char *cp;
  155.         int16 checksum;
  156.  
  157.         if((bp = pushdown(data,ICMPLEN)) == NULLBUF)
  158.                 return NULLBUF;
  159.         cp = bp->data;
  160.  
  161.         *cp++ = icmp->type;
  162.         *cp++ = icmp->code;
  163.         cp = put16(cp,0);               /* Clear checksum */
  164.         cp = put16(cp,icmp->args.echo.id);
  165.         cp = put16(cp,icmp->args.echo.seq);
  166.  
  167.         /* Compute checksum, and stash result */
  168.         checksum = cksum(NULLHEADER,bp,len_mbuf(bp));
  169.         cp = &bp->data[2];
  170.         cp = put16(cp,checksum);
  171.  
  172.         return bp;
  173. }
  174. /* Pull off ICMP header */
  175. int ntohicmp(struct icmp *icmp, struct mbuf **bpp)
  176. {
  177.         if(icmp == (struct icmp *)NULL)
  178.                 return -1;
  179.         icmp->type = pullchar(bpp);
  180.         icmp->code = pullchar(bpp);
  181.         (void) pull16(bpp);             /* Toss checksum */
  182.         icmp->args.echo.id = pull16(bpp);
  183.         icmp->args.echo.seq = pull16(bpp);
  184.         return 0;
  185. }
  186.