/*
 * Detailed Protocol Decoder for ICMP
 *
 * Christopher Wheeler(cwheeler@cac.washington.edu)
 *
 * 25 November 1992
 */


#include <sys/param.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <netinet/in_systm.h>
#include <netinet/ip.h>

#include "ip_icmp.h"
#include "tcpview.h" 

void detail_icmp(icmp, len)
     register struct icmp *icmp;
     u_short len;
{
  u_long data_bytes;
  u_short checksum;

#define PROTO_STR  "ICMP:  "

  printf("%s----- ICMP packet -----\n", PROTO_STR);
  hex(0, Phdr->caplen - Offset - 1);   /* header line */

  if ( Phdr->caplen - Offset < len ){
    printf("%s[ICMP Packet truncated to %d bytes, should be %d]\n", 
	   PROTO_STR, Phdr->caplen - Offset, len);
    hex(0, Phdr->caplen - Offset - 1); /* second header line */

    if ( Phdr->caplen - Offset < sizeof(struct icmp) ){
      printf("%s[Unable to evaluate]\n", PROTO_STR);
      hex(-1,-1);		/* third header line */
      return;
    }

    data_bytes = Phdr->caplen - Offset - ICMP_MINLEN;
  }
  else
    data_bytes = len - ICMP_MINLEN;

  printf("%s\n", PROTO_STR);
  hex(-1,-1);			/* blank */
  hex(0,0);			 /* Type */
  hex(1,1);			 /* Code */
  hex(2,3);			 /* Checksum */

  
  checksum = ntohs(icmp->icmp_cksum);

  switch (icmp->icmp_type){
  case ICMP_ECHOREPLY:
  case ICMP_ECHO:
    if ( icmp->icmp_type == ICMP_ECHOREPLY )
      printf("%sType = %d (Echo Reply)\n", PROTO_STR, ICMP_ECHOREPLY);
    else
      printf("%sType = %d (Echo Request)\n", PROTO_STR, ICMP_ECHO);

    printf("%sCode = %d (Should be 0)\n", PROTO_STR, icmp->icmp_code);
    printf("%sChecksum = %lX\n", PROTO_STR, checksum);
    printf("%sIdentifier = %d\n", PROTO_STR, ntohs(icmp->icmp_id));
    hex(4,5);
    printf("%sSequence Number = %d\n", PROTO_STR, ntohs(icmp->icmp_seq));
    hex(6,7);

    printf("%s[%d bytes of optional data]\n", PROTO_STR, data_bytes);
    hex(8, 8 + data_bytes - 1);
    break;
  case ICMP_UNREACH:
    printf("%sType = %d (Destination Unreachable)\n", PROTO_STR,
	   ICMP_UNREACH);
    switch (icmp->icmp_code){
    case ICMP_UNREACH_NET:
      printf("%sCode = %d (Network Unreachable)\n", PROTO_STR,
	     ICMP_UNREACH_NET);
      break;
    case ICMP_UNREACH_HOST:
      printf("%sCode = %d (Host Unreachable)\n", PROTO_STR,
	     ICMP_UNREACH_HOST);
      break;
    case ICMP_UNREACH_PROTOCOL:
      printf("%sCode = %d (Protocol Unreachable)\n", PROTO_STR,
	     ICMP_UNREACH_PROTOCOL);
      break;
    case ICMP_UNREACH_PORT:
      printf("%sCode = %d (Port Unreachable)\n", PROTO_STR,
	     ICMP_UNREACH_PORT);
      break;
    case ICMP_UNREACH_NEEDFRAG:
      printf("%sCode = %d (Fragmentation Needed and DF set)\n", PROTO_STR,
	     ICMP_UNREACH_NEEDFRAG);
      break;
    case ICMP_UNREACH_SRCFAIL:
      printf("%sCode = %d (Source Route Failed)\n", PROTO_STR,
	     ICMP_UNREACH_SRCFAIL);
      break;
    default:
      printf("%sCode = %s (Unknown Code)\n", PROTO_STR, icmp->icmp_code);
      break;
    }
    printf("%sChecksum = %lX\n", PROTO_STR, checksum);
    printf("%sIP portion of originating message(description follows)\n\n",
	   PROTO_STR);
    hex(8, 8 + data_bytes - 1);
    hex(-1,-1);
    Offset += ICMP_MINLEN;
    detail_ip(&icmp->icmp_ip);
    break;
  case ICMP_SOURCEQUENCH:
    printf("%sType = %d (Source Quench)\n", PROTO_STR, ICMP_SOURCEQUENCH);
    printf("%sCode = %d (Should be 0)\n", PROTO_STR, icmp->icmp_code);
    printf("%sChecksum = %lX\n", PROTO_STR, checksum);
    printf("%sIP portion of originating message(description follows)\n\n",
	   PROTO_STR);
    hex(8, 8 + data_bytes - 1);
    hex(-1,-1);
    Offset += ICMP_MINLEN;
    detail_ip(&icmp->icmp_ip);
    break;
  case ICMP_REDIRECT:
    printf("%sType = %d (Redirect)\n", PROTO_STR, ICMP_REDIRECT);
    switch(icmp->icmp_code){
    case ICMP_REDIRECT_NET:
      printf("%sCode = %d (Network)\n", PROTO_STR, ICMP_REDIRECT_NET);
      break;
    case ICMP_REDIRECT_HOST:
      printf("%sCode = %d (Host)\n", PROTO_STR, ICMP_REDIRECT_HOST);
      break;
    case ICMP_REDIRECT_TOSNET:
      printf("%sCode = %d (Type of Service and Network)\n", PROTO_STR,
	     ICMP_REDIRECT_TOSNET);
      break;
    case ICMP_REDIRECT_TOSHOST:
      printf("%sCode = %d (Type of Service and Host)\n", PROTO_STR,
	     ICMP_REDIRECT_TOSHOST);
      break;
    default:
      printf("%sCode = %d (Unknown)\n", PROTO_STR, icmp->icmp_code);
      break;
    }
    printf("%sChecksum = %lX\n", PROTO_STR, checksum);
    printf("%sGateway IP address = %s\n", PROTO_STR,
	   inet_ntoa(icmp->icmp_gwaddr));
    hex(4,7);
    printf("%sIP portion of originating message(description follows)\n\n",
	   PROTO_STR);
    hex(8, 8 + data_bytes - 1);
    hex(-1,-1);
    Offset += ICMP_MINLEN;
    detail_ip(&icmp->icmp_ip);
    break;
  case ICMP_DISC_AD:
    {
      struct icmp_ra_addr *ra;
      u_long i, byte;
      
      printf("%sType = %d (Discovery Advertisement)\n", PROTO_STR,
	     ICMP_DISC_AD);
      printf("%sCode = %d (Should be 0)\n", PROTO_STR, icmp->icmp_code);
      printf("%sChecksum = %lX\n", PROTO_STR, checksum);
      printf("%sNumber of addresses = %d\n", PROTO_STR, icmp->icmp_num);
      hex(4,4);
      printf("%sAddress size = %d (32-bit words)\n", PROTO_STR,
	     icmp->icmp_size);
      hex(5,5);
      printf("%sLifetime = %d (sec)\n", PROTO_STR,
	     ntohs(icmp->icmp_lifetime));
      hex(6,7);
      printf("%s\n", PROTO_STR);
      hex(-1,-1);		/* blank line */
      for ( ra = icmp->icmp_adv, i = 0;
	   i < icmp->icmp_num; ra++, i++ ){
	if ( (u_long)ra + sizeof(struct icmp_ra_addr) >
	    (u_long)icmp + (Phdr->caplen - Offset) ){
	  printf("%s***** Entry Truncated *****\n", PROTO_STR);
	  hex(byte+8, Phdr->caplen - Offset - 1);
	  break;
	}
	byte = ICMP_MINLEN + (i * 8);
	printf("%sRouter Address = %s\n", PROTO_STR, inet_ntoa(ra->addr));
	hex(byte, byte+3);
	printf("%sPreference Level = %lX\n", PROTO_STR, ntohl(ra->preference));
	hex(byte+4, byte+7);
      }
    }
    break;
  case ICMP_DISC_SOLICIT:
    printf("%sType = %d (Discovery Solicitation)\n", PROTO_STR,
	   ICMP_DISC_SOLICIT);
    printf("%sCode = %d (Should be 0)\n", PROTO_STR, icmp->icmp_code);
    printf("%sChecksum = %lX\n", PROTO_STR, checksum);
    printf("%sReserved Data\n", PROTO_STR);
    hex(4,7);
    break;
  case ICMP_TIMXCEED:
    printf("%sType = %d (Time Exceeded)\n", PROTO_STR, ICMP_TIMXCEED);
    switch(icmp->icmp_code){
    case ICMP_TIMXCEED_INTRANS:
      printf("%sCode = %d (TTL Count)\n", PROTO_STR, ICMP_TIMXCEED_INTRANS);
      break;
    case ICMP_TIMXCEED_REASS:
      printf("%sCode = %d (Fragment reassembly time)\n", PROTO_STR,
	     ICMP_TIMXCEED_REASS);
      break;
    default:
      printf("%sCode = %d (Unknown)\n", PROTO_STR, icmp->icmp_code);
      break;
    }
    printf("%sChecksum = %lX\n", PROTO_STR, checksum);
    printf("%sIP portion of originating message(description follows)\n\n",
	   PROTO_STR);
    hex(8, 8 + data_bytes - 1);
    hex(-1,-1);
    Offset += ICMP_MINLEN;
    detail_ip(&icmp->icmp_ip);
    break;
  case ICMP_PARAMPROB:
    printf("%sType = %d (Parameter Problem)\n", PROTO_STR, ICMP_PARAMPROB);
    printf("%sCode = %d (Should be 0)\n", PROTO_STR, icmp->icmp_code);
    printf("%sChecksum = %lX\n", PROTO_STR, checksum);
    printf("%sPointer = %dX\n", PROTO_STR, (u_short)icmp->icmp_pptr);
    hex(4,5);
    printf("%sIP portion of originating message(description follows)\n\n",
	   PROTO_STR);
    hex(8, 8 + data_bytes - 1);
    hex(-1,-1);
    Offset += ICMP_MINLEN;
    detail_ip(&icmp->icmp_ip);
    break;
  case ICMP_TSTAMP:
  case ICMP_TSTAMPREPLY:
    if ( icmp->icmp_type == ICMP_TSTAMP )
      printf("%sType = %d (Timestamp Request)\n", PROTO_STR, ICMP_TSTAMP);
    else
      printf("%sType = %d (Timestamp Reply)\n", PROTO_STR,
	     ICMP_TSTAMPREPLY);
    printf("%sCode = %d (Should be 0)\n", PROTO_STR, icmp->icmp_code);
    printf("%sChecksum = %lX\n", PROTO_STR, checksum);
    printf("%sIdentifier = %d\n", PROTO_STR, ntohs(icmp->icmp_id));
    hex(4,5);
    printf("%sSequence Number = %d\n", PROTO_STR, ntohs(icmp->icmp_seq));
    hex(6,7);
    printf("%sOriginate Timestamp = %d\n", PROTO_STR, ntohl(icmp->icmp_otime));
    hex(8,11);
    printf("%sReceive Timestamp = %d\n", PROTO_STR, ntohl(icmp->icmp_rtime));
    hex(12,15);
    printf("%sTransmit Timestamp = %d\n", PROTO_STR, ntohl(icmp->icmp_ttime));
    hex(16,19);
   break;
  case ICMP_IREQ:
  case ICMP_IREQREPLY:
    if ( icmp->icmp_type == ICMP_IREQ )
      printf("%sType = %d (Information Request)\n", PROTO_STR, ICMP_IREQ);
    else
      printf("%sType = %d (Information Reply)\n", PROTO_STR, ICMP_IREQREPLY);
    printf("%sCode = %d (Should be 0)\n", PROTO_STR, icmp->icmp_code);
    printf("%sChecksum = %lX\n", PROTO_STR, checksum);
    printf("%sOther data\n", PROTO_STR);
    hex(8, 8 + data_bytes - 1);
    break;
  case ICMP_MASKREQ:
  case ICMP_MASKREPLY:
    if ( icmp->icmp_type == ICMP_MASKREQ )
      printf("%sType = %d (Address Mask Request)\n", PROTO_STR,
	     ICMP_MASKREQ);
    else
      printf("%sType = %d (Address Mask Reply)\n", PROTO_STR,
	     ICMP_MASKREPLY);
    printf("%sCode = %d (Should be 0)\n", PROTO_STR,
	   icmp->icmp_code);
    printf("%sChecksum = %lX\n", PROTO_STR, checksum);
    printf("%sIdentifier = %d\n", PROTO_STR, ntohs(icmp->icmp_id));
    hex(4,5);
    printf("%sSequence Number = %d\n", PROTO_STR, ntohs(icmp->icmp_seq));
    hex(6,7);
    printf("%sAddress Mask = %s\n", PROTO_STR, inet_addr(icmp->icmp_mask));
    hex(8,11);
    break;
  default:
    printf("%sType = %d (Unknown)\n", PROTO_STR, icmp->icmp_type);
    break;
  }

  printf("%s\n", PROTO_STR);
  hex(-1,-1);
  printf("%s----- End of ICMP packet -----\n", PROTO_STR);
  hex(-1,-1);
}





syntax highlighted by Code2HTML, v. 0.9.1