/* @(#) $Header: icmpdump.c,v 1.4 91/02/24 20:16:55 deyke Exp $ */

/* ICMP header tracing
 * Copyright 1991 Phil Karn, KA9Q
 */
#include <stdio.h>
#include "global.h"

#define	ICMP_DEST_UNREACH	3
#define	ICMP_REDIRECT		5
#define	ICMP_TIME_EXCEED	11
#define	ICMP_PARAM_PROB		12
#define	ICMP_ECHO		8
#define	ICMP_ECHO_REPLY		0
#define	ICMP_INFO_RQST		15
#define	ICMP_INFO_REPLY		16
#define	ICMP_TIMESTAMP		13
#define	ICMP_TIME_REPLY		14
#define	ICMP_QUENCH		4

#define	ICMPLEN			8

/* Dump an ICMP header */
void icmp_dump(unsigned char *data, int length)
{
	int type;
	int code;
	int pointer;
	unsigned char *address;
	int id, seq;

	type    = data[0];
	code    = data[1];
	pointer = data[4];
	address = data + 4;
	id      = get16(data + 4);
	seq     = get16(data + 6);

	data   += ICMPLEN;
	length -= ICMPLEN;

	fprintf(stdout, "ICMP: type ");

	switch (type)
	{
	case ICMP_DEST_UNREACH:
		fprintf(stdout, "Unreachable code ");
		switch (code)
		{
		case 0:
			fprintf(stdout, "Network");
			break;
		case 1:
			fprintf(stdout, "Host");
			break;
		case 2:
			fprintf(stdout, "Protocol");
			break;
		case 3:
			fprintf(stdout, "Port");
			break;
		case 4:
			fprintf(stdout, "Fragmentation");
			break;
		case 5:
			fprintf(stdout, "Source route");
			break;
		case 6:
			fprintf(stdout, "Dest net unknown");
			break;
		case 7:
			fprintf(stdout, "Dest host unknown");
			break;
		case 8:
			fprintf(stdout, "Source host isolated");
			break;
		case 9:
			fprintf(stdout, "Net prohibited");
			break;
		case 10:
			fprintf(stdout, "Host prohibited");
			break;
		case 11:
			fprintf(stdout, "Net TOS");
			break;
		case 12:
			fprintf(stdout, "Host TOS");
			break;
		case 13:
			fprintf(stdout, "Administratively Prohibited");
			break;
		default:
			fprintf(stdout, "%d", code);
			break;
		}
		fprintf(stdout, "\nReturned ");
		ip_dump(data, length);
		break;
	case ICMP_REDIRECT:
		fprintf(stdout, "Redirect code ");
		switch (code)
		{
		case 0:
			fprintf(stdout, "Network");
			break;
		case 1:
			fprintf(stdout, "Host");
			break;
		case 2:
			fprintf(stdout, "TOS & Network");
			break;
		case 3:
			fprintf(stdout, "TOS & Host");
			break;
		default:
			fprintf(stdout, "%d", code);
			break;
		}
		fprintf(stdout, " new gateway %d.%d.%d.%d",
				address[0], address[1],
				address[2], address[3]);
		fprintf(stdout, "\nReturned ");
		ip_dump(data, length);
		break;
	case ICMP_TIME_EXCEED:
		fprintf(stdout, "Time Exceeded code ");
		switch (code)
		{
		case 0:
			fprintf(stdout, "Time-to-live");
			break;
		case 1:
			fprintf(stdout, "Fragment reassembly");
			break;
		default:
			fprintf(stdout, "%d", code);
			break;
		}
		fprintf(stdout, "\nReturned ");
		ip_dump(data, length);
		break;
	case ICMP_PARAM_PROB:
		fprintf(stdout, "Parameter Problem pointer %d", pointer);
		fprintf(stdout, "\nReturned ");
		ip_dump(data, length);
		break;
	case ICMP_QUENCH:
		fprintf(stdout, "Source Quench");
		fprintf(stdout, "\nReturned ");
		ip_dump(data, length);
		break;
	case ICMP_ECHO:
		fprintf(stdout, "Echo Request id %d seq %d\n", id, seq);
		data_dump(data, length);
		break;
	case ICMP_ECHO_REPLY:
		fprintf(stdout, "Echo Reply id %d seq %d\n", id, seq);
		data_dump(data, length);
		break;
	case ICMP_INFO_RQST:
		fprintf(stdout, "Information Request id %d seq %d\n", id, seq);
		data_dump(data, length);
		break;
	case ICMP_INFO_REPLY:
		fprintf(stdout, "Information Reply id %d seq %d\n", id, seq);
		data_dump(data, length);
		break;
	case ICMP_TIMESTAMP:
		fprintf(stdout, "Timestamp Request id %d seq %d\n", id, seq);
		data_dump(data, length);
		break;
	case ICMP_TIME_REPLY:
		fprintf(stdout, "Timestamp Reply id %d seq %d\n", id, seq);
		data_dump(data, length);
		break;
	default:
		fprintf(stdout, "%d\n", type);
		data_dump(data, length);
		break;
	}
}

