/* IP header tracing routines
 * Copyright 1991 Phil Karn, KA9Q
 */
/* Mods by PA0GRI */
#include "global.h"
#include "mbuf.h"
#include "internet.h"
#include "iface.h"
#include "trace.h"

#if !defined(_lint)
static char rcsid[] OPTIONAL = "$Id: ipdump.c,v 1.10 2000/05/09 16:48:26 brian Exp $";
#endif

void
ip_dump (fp, bpp, check)
FILE *fp;
struct mbuf **bpp;
int check;
{
struct ip ip;
int16 ip_len;
int16 length;
int16 csum;

	if (bpp == NULLBUFP || *bpp == NULLBUF)
		return;

#ifdef CTRACE
	if (use_ctrace)
		traceprintf (fp, Acyan);
#endif
	traceprintf (fp, "IP:");
	/* Sneak peek at IP header and find length */
	ip_len = ((*bpp)->data[0] & 0xf) << 2;
	if (ip_len != IPLEN) {
#ifdef CTRACE
		if (use_ctrace)
			traceprintf (fp, " %sbad header\n%s%s", Aalert, Acyan, Aboldoff);
		else
#endif
		traceprintf (fp, " bad header\n");
		return;
	}
	if (check)
		csum = cksum (NULLHEADER, *bpp, ip_len);
	else
		csum = 0;

	(void) ntohip (&ip, bpp);	/* Can't fail, we've already checked ihl */

	/* check IP length */
	if (ip.length < ip_len) {
#ifdef CTRACE
		if (use_ctrace)
			traceprintf (fp, " %sbad header\n%s%s", Aalert, Acyan, Aboldoff);
		else
#endif
		traceprintf (fp, " bad header\n");
		return;
	}
	/* Trim data segment if necessary. */
	length = ip.length - ip_len;	/* Length of data portion */
	trim_mbuf (bpp, length);
	traceprintf (fp, " len %u", ip.length);
#ifdef CTRACE
	if (use_ctrace) {
		traceprintf (fp, " %s%s%s%s%s", Awhite, Abold, inet_ntoa (ip.source), Acyan, Aboldoff);
		traceprintf (fp, "->%s%s%s%s%s ihl %u ttl %u", Awhite, Abold,
			     inet_ntoa (ip.dest), Acyan, Aboldoff, ip_len, uchar (ip.ttl));
	} else {
#endif
	traceprintf (fp, " %s", inet_ntoa (ip.source));
	traceprintf (fp, "->%s ihl %u ttl %u",
		     inet_ntoa (ip.dest), ip_len, uchar (ip.ttl));
#ifdef CTRACE
	}
#endif
	if (ip.tos != 0)
		traceprintf (fp, " tos %u", uchar (ip.tos));
	if (ip.offset != 0 || ip.flags.mf)
		traceprintf (fp, " id %u offs %u", ip.id, ip.offset);
	if (ip.flags.congest)
		traceprintf (fp, " CE");
	if (ip.flags.df)
		traceprintf (fp, " DF");
	if (ip.flags.mf) {
		traceprintf (fp, " MF");
		check = 0;	/* Bypass host-level checksum verify */
	}
	if (csum != 0) {
#ifdef CTRACE
		if (use_ctrace)
			traceprintf (fp, " %sCHECKSUM ERROR (%u)%s%s", Aalert, csum, Acyan, Aboldoff);
		else
#endif	
		traceprintf (fp, " CHECKSUM ERROR (%u)", csum);
	}

	if (ip.offset != 0) {
		traceprintf (fp, "\n");
		return;
	}
	switch (uchar (ip.protocol)) {
		case TCP_PTCL:
			traceprintf (fp, " prot TCP\n");
			tcp_dump (fp, bpp, ip.source, ip.dest, check);
			break;
		case UDP_PTCL:
			traceprintf (fp, " prot UDP\n");
			udp_dump (fp, bpp, ip.source, ip.dest, check);
			break;
		case ICMP_PTCL:
			traceprintf (fp, " prot ICMP\n");
			icmp_dump (fp, bpp, ip.source, ip.dest, check);
			break;
		case ENCAP_PTCL:
		case IP_PTCL:
			traceprintf (fp, " prot IP(%d)\n", uchar (ip.protocol));
			ip_dump (fp, bpp, check);
			break;
#ifdef AX25
		case AX25_PTCL:
			traceprintf (fp, " prot AX25\n");
			ax25_dump (fp, bpp, check);
			break;
#endif
#ifdef  RSPF
		case RSPF_PTCL:
			traceprintf (fp, " prot RSPF\n");
			rspf_dump (fp, bpp, ip.source, ip.dest, check);
			break;
#endif
		default:
			traceprintf (fp, " prot %u\n", uchar (ip.protocol));
			break;
	}
}
